Skip to content

Commit 2a8da8e

Browse files
committed
refactor iconv
1 parent 0139c9e commit 2a8da8e

File tree

1 file changed

+49
-16
lines changed

1 file changed

+49
-16
lines changed

llvm/lib/Support/CharSet.cpp

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,34 @@ CharSetConverterICU::convert(StringRef Source,
172172

173173
#elif defined(HAVE_ICONV)
174174
class CharSetConverterIconv : public details::CharSetConverterImplBase {
175-
iconv_t ConvDesc;
175+
class UniqueIconvT {
176+
iconv_t ConvDesc;
177+
178+
public:
179+
operator iconv_t() const { return ConvDesc; }
180+
UniqueIconvT(iconv_t CD) : ConvDesc(CD) {}
181+
~UniqueIconvT() {
182+
if (ConvDesc != (iconv_t)-1) {
183+
iconv_close(ConvDesc);
184+
ConvDesc = (iconv_t)-1;
185+
}
186+
}
187+
UniqueIconvT(UniqueIconvT &&Other) : ConvDesc(Other.ConvDesc) {
188+
Other.ConvDesc = (iconv_t)-1;
189+
}
190+
UniqueIconvT &operator=(UniqueIconvT &&Other) {
191+
if (&Other != this) {
192+
ConvDesc = Other.ConvDesc;
193+
Other.ConvDesc = (iconv_t)-1;
194+
}
195+
return *this;
196+
}
197+
};
198+
UniqueIconvT ConvDesc;
176199

177200
public:
178-
CharSetConverterIconv(iconv_t ConvDesc) : ConvDesc(ConvDesc) {}
201+
CharSetConverterIconv(UniqueIconvT ConvDesc)
202+
: ConvDesc(std::move(ConvDesc)) {}
179203

180204
std::error_code convert(StringRef Source,
181205
SmallVectorImpl<char> &Result) const override;
@@ -184,19 +208,16 @@ class CharSetConverterIconv : public details::CharSetConverterImplBase {
184208
std::error_code
185209
CharSetConverterIconv::convert(StringRef Source,
186210
SmallVectorImpl<char> &Result) const {
187-
// Setup the input. Use nullptr to reset iconv state if input length is zero.
188-
size_t InputLength = Source.size();
189-
char *Input = InputLength ? const_cast<char *>(Source.data()) : nullptr;
190211
// Setup the output. We directly write into the SmallVector.
191-
Result.resize_for_overwrite(Source.size());
192212
size_t Capacity = Result.capacity();
193213
char *Output = static_cast<char *>(Result.data());
194214
size_t OutputLength = Capacity;
215+
Result.resize_for_overwrite(Capacity);
195216

196217
size_t Ret;
197-
198218
// Handle errors returned from iconv().
199-
auto HandleError = [&Capacity, &Output, &OutputLength, &Result](size_t Ret) {
219+
auto HandleError = [&Capacity, &Output, &OutputLength, &Result,
220+
this](size_t Ret) {
200221
if (Ret == static_cast<size_t>(-1)) {
201222
// An error occured. Check if we can gracefully handle it.
202223
if (errno == E2BIG && Capacity < std::numeric_limits<size_t>::max()) {
@@ -217,14 +238,26 @@ CharSetConverterIconv::convert(StringRef Source,
217238
}
218239
};
219240

220-
// Convert the string.
221-
while ((Ret = iconv(ConvDesc, &Input, &InputLength, &Output, &OutputLength)))
222-
if (auto EC = HandleError(Ret))
223-
return EC;
224-
// Flush the converter
225-
while ((Ret = iconv(ConvDesc, nullptr, nullptr, &Output, &OutputLength)))
226-
if (auto EC = HandleError(Ret))
227-
return EC;
241+
do {
242+
// Setup the input. Use nullptr to reset iconv state if input length is
243+
// zero.
244+
size_t InputLength = Source.size();
245+
char *Input = InputLength ? const_cast<char *>(Source.data()) : nullptr;
246+
Ret = iconv(ConvDesc, &Input, &InputLength, &Output, &OutputLength);
247+
if (Ret != 0) {
248+
if (auto EC = HandleError(Ret))
249+
return EC;
250+
continue;
251+
}
252+
// Flush the converter
253+
Ret = iconv(ConvDesc, nullptr, nullptr, &Output, &OutputLength);
254+
if (Ret != 0) {
255+
if (auto EC = HandleError(Ret))
256+
return EC;
257+
continue;
258+
}
259+
break;
260+
} while (true);
228261

229262
// Re-adjust size to actual size.
230263
Result.resize(Capacity - OutputLength);

0 commit comments

Comments
 (0)