Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 57db503

Browse files
anonriglemire
andcommittedApr 8, 2024
buffer: improve base64 and base64url performance
Co-authored-by: Daniel Lemire <[email protected]>
1 parent db17461 commit 57db503

File tree

1 file changed

+74
-14
lines changed

1 file changed

+74
-14
lines changed
 

‎src/string_bytes.cc

+74-14
Original file line numberDiff line numberDiff line change
@@ -346,17 +346,65 @@ size_t StringBytes::Write(Isolate* isolate,
346346
}
347347

348348
case BASE64URL:
349-
// Fall through
350-
case BASE64:
351-
if (str->IsExternalOneByte()) {
349+
if (str->IsExternalOneByte()) { // 8-bit case
352350
auto ext = str->GetExternalOneByteStringResource();
353-
nbytes = base64_decode(buf, buflen, ext->data(), ext->length());
351+
auto result = simdutf::base64_to_binary_safe(
352+
ext->data(), ext->length(), buf, buflen, simdutf::base64_url);
353+
if (result.error == simdutf::error_code::SUCCESS) {
354+
nbytes = result.count;
355+
} else {
356+
// The input does not follow the WHATWG forgiving-base64 specification
357+
// adapted for base64url
358+
// https://infra.spec.whatwg.org/#forgiving-base64-decode
359+
nbytes = base64_decode(buf, buflen, ext->data(), ext->length());
360+
}
354361
} else {
355362
String::Value value(isolate, str);
356-
nbytes = base64_decode(buf, buflen, *value, value.length());
363+
auto result =
364+
simdutf::base64_to_binary(reinterpret_cast<const char16_t*>(*value),
365+
value.length(),
366+
buf,
367+
simdutf::base64_url);
368+
if (result.error == simdutf::error_code::SUCCESS) {
369+
nbytes = result.count;
370+
} else {
371+
// The input does not follow the WHATWG forgiving-base64 specification
372+
// (adapted for base64url with + and / replaced by - and _).
373+
// https://infra.spec.whatwg.org/#forgiving-base64-decode
374+
nbytes = base64_decode(buf, buflen, *value, value.length());
375+
}
357376
}
358377
break;
359378

379+
case BASE64: {
380+
if (str->IsExternalOneByte()) { // 8-bit case
381+
auto ext = str->GetExternalOneByteStringResource();
382+
auto result = simdutf::base64_to_binary_safe(
383+
ext->data(), ext->length(), buf, buflen);
384+
if (result.error == simdutf::error_code::SUCCESS) {
385+
nbytes = result.count;
386+
} else {
387+
// The input does not follow the WHATWG forgiving-base64 specification
388+
// https://infra.spec.whatwg.org/#forgiving-base64-decode
389+
nbytes = base64_decode(buf, buflen, ext->data(), ext->length());
390+
}
391+
} else {
392+
String::Value value(isolate, str);
393+
auto result = simdutf::base64_to_binary_safe(
394+
reinterpret_cast<const char16_t*>(*value),
395+
value.length(),
396+
buf,
397+
buflen);
398+
if (result.error == simdutf::error_code::SUCCESS) {
399+
nbytes = result.count;
400+
} else {
401+
// The input does not follow the WHATWG base64 specification
402+
// https://infra.spec.whatwg.org/#forgiving-base64-decode
403+
nbytes = base64_decode(buf, buflen, *value, value.length());
404+
}
405+
}
406+
break;
407+
}
360408
case HEX:
361409
if (str->IsExternalOneByte()) {
362410
auto ext = str->GetExternalOneByteStringResource();
@@ -411,9 +459,12 @@ Maybe<size_t> StringBytes::StorageSize(Isolate* isolate,
411459
break;
412460

413461
case BASE64URL:
414-
// Fall through
462+
data_size = simdutf::base64_length_from_binary(str->Length(),
463+
simdutf::base64_url);
464+
break;
465+
415466
case BASE64:
416-
data_size = base64_decoded_size_fast(str->Length());
467+
data_size = simdutf::base64_length_from_binary(str->Length());
417468
break;
418469

419470
case HEX:
@@ -452,11 +503,16 @@ Maybe<size_t> StringBytes::Size(Isolate* isolate,
452503
case UCS2:
453504
return Just(str->Length() * sizeof(uint16_t));
454505

455-
case BASE64URL:
456-
// Fall through
506+
case BASE64URL: {
507+
String::Value value(isolate, str);
508+
return Just(simdutf::base64_length_from_binary(value.length(),
509+
simdutf::base64_url));
510+
}
511+
457512
case BASE64: {
458513
String::Value value(isolate, str);
459-
return Just(base64_decoded_size(*value, value.length()));
514+
return Just(simdutf::base64_length_from_binary(value.length(),
515+
simdutf::base64_default));
460516
}
461517

462518
case HEX:
@@ -609,28 +665,32 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
609665
return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
610666

611667
case BASE64: {
612-
size_t dlen = base64_encoded_size(buflen);
668+
size_t dlen =
669+
simdutf::base64_length_from_binary(buflen, simdutf::base64_default);
613670
char* dst = node::UncheckedMalloc(dlen);
614671
if (dst == nullptr) {
615672
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
616673
return MaybeLocal<Value>();
617674
}
618675

619-
size_t written = base64_encode(buf, buflen, dst, dlen);
676+
size_t written =
677+
simdutf::binary_to_base64(buf, buflen, dst, simdutf::base64_default);
620678
CHECK_EQ(written, dlen);
621679

622680
return ExternOneByteString::New(isolate, dst, dlen, error);
623681
}
624682

625683
case BASE64URL: {
626-
size_t dlen = base64_encoded_size(buflen, Base64Mode::URL);
684+
size_t dlen =
685+
simdutf::base64_length_from_binary(buflen, simdutf::base64_url);
627686
char* dst = node::UncheckedMalloc(dlen);
628687
if (dst == nullptr) {
629688
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
630689
return MaybeLocal<Value>();
631690
}
632691

633-
size_t written = base64_encode(buf, buflen, dst, dlen, Base64Mode::URL);
692+
size_t written =
693+
simdutf::binary_to_base64(buf, buflen, dst, simdutf::base64_url);
634694
CHECK_EQ(written, dlen);
635695

636696
return ExternOneByteString::New(isolate, dst, dlen, error);

0 commit comments

Comments
 (0)
Please sign in to comment.