Skip to content

Commit 39b0034

Browse files
TimothyGuitaloacasas
authored andcommitted
src, i18n: cleanup usage of MaybeStackBuffer
- Templatize AsBuffer() and create a generic version for inclusion in the Buffer class - Use MaybeStackBuffer::storage() - If possible, avoid double conversion in ToASCII()/ToUnicode() - More descriptive assertion error in tests PR-URL: #11464 Reviewed-By: Steven R Loomis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent fb85f50 commit 39b0034

File tree

3 files changed

+85
-58
lines changed

3 files changed

+85
-58
lines changed

src/node_i18n.cc

+54-56
Original file line numberDiff line numberDiff line change
@@ -72,37 +72,19 @@ using v8::Value;
7272

7373
namespace i18n {
7474

75-
const size_t kStorageSize = 1024;
76-
77-
// TODO(jasnell): This could potentially become a member of MaybeStackBuffer
78-
// at some point in the future. Care would need to be taken with the
79-
// MaybeStackBuffer<UChar> variant below.
80-
MaybeLocal<Object> AsBuffer(Isolate* isolate,
81-
MaybeStackBuffer<char>* buf,
82-
size_t len) {
83-
if (buf->IsAllocated()) {
84-
MaybeLocal<Object> ret = Buffer::New(isolate, buf->out(), len);
85-
if (!ret.IsEmpty()) buf->Release();
75+
template <typename T>
76+
MaybeLocal<Object> ToBufferEndian(Environment* env, MaybeStackBuffer<T>* buf) {
77+
MaybeLocal<Object> ret = Buffer::New(env, buf);
78+
if (ret.IsEmpty())
8679
return ret;
87-
}
88-
return Buffer::Copy(isolate, buf->out(), len);
89-
}
9080

91-
MaybeLocal<Object> AsBuffer(Isolate* isolate,
92-
MaybeStackBuffer<UChar>* buf,
93-
size_t len) {
94-
char* dst = reinterpret_cast<char*>(**buf);
95-
MaybeLocal<Object> ret;
96-
if (buf->IsAllocated()) {
97-
ret = Buffer::New(isolate, dst, len);
98-
if (!ret.IsEmpty()) buf->Release();
99-
} else {
100-
ret = Buffer::Copy(isolate, dst, len);
101-
}
102-
if (!ret.IsEmpty() && IsBigEndian()) {
103-
SPREAD_BUFFER_ARG(ret.ToLocalChecked(), buf);
104-
SwapBytes16(buf_data, buf_length);
81+
static_assert(sizeof(T) == 1 || sizeof(T) == 2,
82+
"Currently only one- or two-byte buffers are supported");
83+
if (sizeof(T) > 1 && IsBigEndian()) {
84+
SPREAD_BUFFER_ARG(ret.ToLocalChecked(), retbuf);
85+
SwapBytes16(retbuf_data, retbuf_length);
10586
}
87+
10688
return ret;
10789
}
10890

@@ -138,14 +120,14 @@ void CopySourceBuffer(MaybeStackBuffer<UChar>* dest,
138120
}
139121
}
140122

141-
typedef MaybeLocal<Object> (*TranscodeFunc)(Isolate* isolate,
123+
typedef MaybeLocal<Object> (*TranscodeFunc)(Environment* env,
142124
const char* fromEncoding,
143125
const char* toEncoding,
144126
const char* source,
145127
const size_t source_length,
146128
UErrorCode* status);
147129

148-
MaybeLocal<Object> Transcode(Isolate* isolate,
130+
MaybeLocal<Object> Transcode(Environment* env,
149131
const char* fromEncoding,
150132
const char* toEncoding,
151133
const char* source,
@@ -162,12 +144,14 @@ MaybeLocal<Object> Transcode(Isolate* isolate,
162144
ucnv_convertEx(to.conv, from.conv, &target, target + limit,
163145
&source, source + source_length, nullptr, nullptr,
164146
nullptr, nullptr, true, true, status);
165-
if (U_SUCCESS(*status))
166-
ret = AsBuffer(isolate, &result, target - &result[0]);
147+
if (U_SUCCESS(*status)) {
148+
result.SetLength(target - &result[0]);
149+
ret = ToBufferEndian(env, &result);
150+
}
167151
return ret;
168152
}
169153

170-
MaybeLocal<Object> TranscodeToUcs2(Isolate* isolate,
154+
MaybeLocal<Object> TranscodeToUcs2(Environment* env,
171155
const char* fromEncoding,
172156
const char* toEncoding,
173157
const char* source,
@@ -181,11 +165,11 @@ MaybeLocal<Object> TranscodeToUcs2(Isolate* isolate,
181165
ucnv_toUChars(from.conv, *destbuf, length_in_chars,
182166
source, source_length, status);
183167
if (U_SUCCESS(*status))
184-
ret = AsBuffer(isolate, &destbuf, length_in_chars);
168+
ret = ToBufferEndian(env, &destbuf);
185169
return ret;
186170
}
187171

188-
MaybeLocal<Object> TranscodeFromUcs2(Isolate* isolate,
172+
MaybeLocal<Object> TranscodeFromUcs2(Environment* env,
189173
const char* fromEncoding,
190174
const char* toEncoding,
191175
const char* source,
@@ -200,37 +184,42 @@ MaybeLocal<Object> TranscodeFromUcs2(Isolate* isolate,
200184
MaybeStackBuffer<char> destbuf(length_in_chars);
201185
const uint32_t len = ucnv_fromUChars(to.conv, *destbuf, length_in_chars,
202186
*sourcebuf, length_in_chars, status);
203-
if (U_SUCCESS(*status))
204-
ret = AsBuffer(isolate, &destbuf, len);
187+
if (U_SUCCESS(*status)) {
188+
destbuf.SetLength(len);
189+
ret = ToBufferEndian(env, &destbuf);
190+
}
205191
return ret;
206192
}
207193

208-
MaybeLocal<Object> TranscodeUcs2FromUtf8(Isolate* isolate,
194+
MaybeLocal<Object> TranscodeUcs2FromUtf8(Environment* env,
209195
const char* fromEncoding,
210196
const char* toEncoding,
211197
const char* source,
212198
const size_t source_length,
213199
UErrorCode* status) {
214200
*status = U_ZERO_ERROR;
215-
MaybeStackBuffer<UChar, kStorageSize> destbuf;
201+
MaybeStackBuffer<UChar> destbuf;
216202
int32_t result_length;
217-
u_strFromUTF8(*destbuf, kStorageSize, &result_length,
203+
u_strFromUTF8(*destbuf, destbuf.capacity(), &result_length,
218204
source, source_length, status);
219205
MaybeLocal<Object> ret;
220206
if (U_SUCCESS(*status)) {
221-
ret = AsBuffer(isolate, &destbuf, result_length * sizeof(**destbuf));
207+
destbuf.SetLength(result_length);
208+
ret = ToBufferEndian(env, &destbuf);
222209
} else if (*status == U_BUFFER_OVERFLOW_ERROR) {
223210
*status = U_ZERO_ERROR;
224211
destbuf.AllocateSufficientStorage(result_length);
225212
u_strFromUTF8(*destbuf, result_length, &result_length,
226213
source, source_length, status);
227-
if (U_SUCCESS(*status))
228-
ret = AsBuffer(isolate, &destbuf, result_length * sizeof(**destbuf));
214+
if (U_SUCCESS(*status)) {
215+
destbuf.SetLength(result_length);
216+
ret = ToBufferEndian(env, &destbuf);
217+
}
229218
}
230219
return ret;
231220
}
232221

233-
MaybeLocal<Object> TranscodeUtf8FromUcs2(Isolate* isolate,
222+
MaybeLocal<Object> TranscodeUtf8FromUcs2(Environment* env,
234223
const char* fromEncoding,
235224
const char* toEncoding,
236225
const char* source,
@@ -241,20 +230,21 @@ MaybeLocal<Object> TranscodeUtf8FromUcs2(Isolate* isolate,
241230
const size_t length_in_chars = source_length / sizeof(UChar);
242231
int32_t result_length;
243232
MaybeStackBuffer<UChar> sourcebuf;
244-
MaybeStackBuffer<char, kStorageSize> destbuf;
233+
MaybeStackBuffer<char> destbuf;
245234
CopySourceBuffer(&sourcebuf, source, source_length, length_in_chars);
246-
u_strToUTF8(*destbuf, kStorageSize, &result_length,
235+
u_strToUTF8(*destbuf, destbuf.capacity(), &result_length,
247236
*sourcebuf, length_in_chars, status);
248237
if (U_SUCCESS(*status)) {
249-
ret = AsBuffer(isolate, &destbuf, result_length);
238+
destbuf.SetLength(result_length);
239+
ret = ToBufferEndian(env, &destbuf);
250240
} else if (*status == U_BUFFER_OVERFLOW_ERROR) {
251241
*status = U_ZERO_ERROR;
252242
destbuf.AllocateSufficientStorage(result_length);
253243
u_strToUTF8(*destbuf, result_length, &result_length, *sourcebuf,
254244
length_in_chars, status);
255245
if (U_SUCCESS(*status)) {
256-
ret = Buffer::New(isolate, *destbuf, result_length);
257-
destbuf.Release();
246+
destbuf.SetLength(result_length);
247+
ret = ToBufferEndian(env, &destbuf);
258248
}
259249
}
260250
return ret;
@@ -320,7 +310,7 @@ void Transcode(const FunctionCallbackInfo<Value>&args) {
320310
ABORT();
321311
}
322312

323-
result = tfn(isolate, EncodingName(fromEncoding), EncodingName(toEncoding),
313+
result = tfn(env, EncodingName(fromEncoding), EncodingName(toEncoding),
324314
ts_obj_data, ts_obj_length, &status);
325315
} else {
326316
status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -431,7 +421,7 @@ int32_t ToUnicode(MaybeStackBuffer<char>* buf,
431421

432422
int32_t len = uidna_nameToUnicodeUTF8(uidna,
433423
input, length,
434-
**buf, buf->length(),
424+
**buf, buf->capacity(),
435425
&info,
436426
&status);
437427

@@ -440,13 +430,17 @@ int32_t ToUnicode(MaybeStackBuffer<char>* buf,
440430
buf->AllocateSufficientStorage(len);
441431
len = uidna_nameToUnicodeUTF8(uidna,
442432
input, length,
443-
**buf, buf->length(),
433+
**buf, buf->capacity(),
444434
&info,
445435
&status);
446436
}
447437

448-
if (U_FAILURE(status))
438+
if (U_FAILURE(status)) {
449439
len = -1;
440+
buf->SetLength(0);
441+
} else {
442+
buf->SetLength(len);
443+
}
450444

451445
uidna_close(uidna);
452446
return len;
@@ -465,7 +459,7 @@ int32_t ToASCII(MaybeStackBuffer<char>* buf,
465459

466460
int32_t len = uidna_nameToASCII_UTF8(uidna,
467461
input, length,
468-
**buf, buf->length(),
462+
**buf, buf->capacity(),
469463
&info,
470464
&status);
471465

@@ -474,13 +468,17 @@ int32_t ToASCII(MaybeStackBuffer<char>* buf,
474468
buf->AllocateSufficientStorage(len);
475469
len = uidna_nameToASCII_UTF8(uidna,
476470
input, length,
477-
**buf, buf->length(),
471+
**buf, buf->capacity(),
478472
&info,
479473
&status);
480474
}
481475

482-
if (U_FAILURE(status))
476+
if (U_FAILURE(status)) {
483477
len = -1;
478+
buf->SetLength(0);
479+
} else {
480+
buf->SetLength(len);
481+
}
484482

485483
uidna_close(uidna);
486484
return len;

src/node_internals.h

+29
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,35 @@ v8::MaybeLocal<v8::Object> New(Environment* env,
198198
// because ArrayBufferAllocator::Free() deallocates it again with free().
199199
// Mixing operator new and free() is undefined behavior so don't do that.
200200
v8::MaybeLocal<v8::Object> New(Environment* env, char* data, size_t length);
201+
202+
// Construct a Buffer from a MaybeStackBuffer (and also its subclasses like
203+
// Utf8Value and TwoByteValue).
204+
// If |buf| is invalidated, an empty MaybeLocal is returned, and nothing is
205+
// changed.
206+
// If |buf| contains actual data, this method takes ownership of |buf|'s
207+
// underlying buffer. However, |buf| itself can be reused even after this call,
208+
// but its capacity, if increased through AllocateSufficientStorage, is not
209+
// guaranteed to stay the same.
210+
template <typename T>
211+
static v8::MaybeLocal<v8::Object> New(Environment* env,
212+
MaybeStackBuffer<T>* buf) {
213+
v8::MaybeLocal<v8::Object> ret;
214+
char* src = reinterpret_cast<char*>(buf->out());
215+
const size_t len_in_bytes = buf->length() * sizeof(buf->out()[0]);
216+
217+
if (buf->IsAllocated())
218+
ret = New(env, src, len_in_bytes);
219+
else if (!buf->IsInvalidated())
220+
ret = Copy(env, src, len_in_bytes);
221+
222+
if (ret.IsEmpty())
223+
return ret;
224+
225+
if (buf->IsAllocated())
226+
buf->Release();
227+
228+
return ret;
229+
}
201230
} // namespace Buffer
202231

203232
} // namespace node

test/parallel/test-icu-transcode.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ const tests = {
2222

2323
for (const test in tests) {
2424
const dest = buffer.transcode(orig, 'utf8', test);
25-
assert.strictEqual(dest.length, tests[test].length);
25+
assert.strictEqual(dest.length, tests[test].length, `utf8->${test} length`);
2626
for (let n = 0; n < tests[test].length; n++)
27-
assert.strictEqual(dest[n], tests[test][n]);
27+
assert.strictEqual(dest[n], tests[test][n], `utf8->${test} char ${n}`);
2828
}
2929

3030
{

0 commit comments

Comments
 (0)