Make the std::string overloads of IconvWrapper::Convert significantly faster

Originally committed to SVN as r4659.
This commit is contained in:
Thomas Goyne 2010-07-07 02:41:40 +00:00
parent 5ed8bf89f6
commit 02237f2a7a

View file

@ -269,15 +269,37 @@ std::string IconvWrapper::Convert(std::string const& source) {
return dest; return dest;
} }
void IconvWrapper::Convert(std::string const& source, std::string &dest) { void IconvWrapper::Convert(std::string const& source, std::string &dest) {
/// @todo Investigate if it's worth using ropes to avoid having to convert char buff[512];
/// everything twice. It probably isn't.
size_t len = RequiredBufferSize(source); const char *src = source.data();
dest.resize(len); size_t srcLen = source.size();
size_t res;
do {
char *dst = buff;
size_t dstLen = sizeof(buff);
res = (*conv)(cd, &src, &srcLen, &dst, &dstLen);
if (res == 0) (*conv)(cd, NULL, NULL, &dst, &dstLen);
dest.append(buff, sizeof(buff) - dstLen);
} while (res == iconv_failed && errno == E2BIG);
// This is technically invalid as C++03 does not require that strings use if (res == iconv_failed) {
// a single contiguous block of memory. However, no implementation has ever switch (errno) {
// not done so and C++0x does require that it be contiguous case EINVAL:
Convert(source.data(), source.size(), &dest[0], len); throw BadInput(
"One or more characters in the input string were not valid "
"characters in the given input encoding");
case EILSEQ:
throw BadOutput(
"One or more characters could not be converted to the "
"selected target encoding and the version of iconv "
"Aegisub was built with does not have useful fallbacks. "
"For best results, please build Aegisub using a recent "
"version of GNU iconv.");
default:
throw ConversionFailure("An unknown conversion failure occurred");
}
}
} }
size_t IconvWrapper::Convert(const char* source, size_t sourceSize, char *dest, size_t destSize) { size_t IconvWrapper::Convert(const char* source, size_t sourceSize, char *dest, size_t destSize) {
@ -307,7 +329,7 @@ size_t IconvWrapper::Convert(const char* source, size_t sourceSize, char *dest,
"For best results, please build Aegisub using a recent " "For best results, please build Aegisub using a recent "
"version of GNU iconv."); "version of GNU iconv.");
default: default:
throw ConversionFailure("An unknown conversion failure occured"); throw ConversionFailure("An unknown conversion failure occurred");
} }
} }
return res; return res;