mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
buffer: make indexOf(byte) faster
Add a V8 fast API implementation for indexOfNumber, which significantly improves the performance of finding a single byte within a buffer. Refs: https://github.com/nodejs/node/pull/52993 PR-URL: https://github.com/nodejs/node/pull/53455 Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
This commit is contained in:
1 parent
1aa8a785be
commit
103623b5ae
2 files changed
+54
-21
No files matched your search
+47
-21
@@ -1089,37 +1089,57 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
|
||||
result == haystack_length ? -1 : static_cast<int>(result));
|
||||
}
|
||||
|
||||
void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
|
||||
int32_t IndexOfNumber(const uint8_t* buffer_data,
|
||||
size_t buffer_length,
|
||||
uint32_t needle,
|
||||
int64_t offset_i64,
|
||||
bool is_forward) {
|
||||
int64_t opt_offset = IndexOfOffset(buffer_length, offset_i64, 1, is_forward);
|
||||
if (opt_offset <= -1 || buffer_length == 0) {
|
||||
return -1;
|
||||
}
|
||||
size_t offset = static_cast<size_t>(opt_offset);
|
||||
CHECK_LT(offset, buffer_length);
|
||||
|
||||
const void* ptr;
|
||||
if (is_forward) {
|
||||
ptr = memchr(buffer_data + offset, needle, buffer_length - offset);
|
||||
} else {
|
||||
ptr = node::stringsearch::MemrchrFill(buffer_data, needle, offset + 1);
|
||||
}
|
||||
const uint8_t* ptr_uint8 = static_cast<const uint8_t*>(ptr);
|
||||
return ptr != nullptr ? static_cast<int32_t>(ptr_uint8 - buffer_data) : -1;
|
||||
}
|
||||
|
||||
void SlowIndexOfNumber(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK(args[1]->IsUint32());
|
||||
CHECK(args[2]->IsNumber());
|
||||
CHECK(args[3]->IsBoolean());
|
||||
|
||||
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
|
||||
ArrayBufferViewContents<char> buffer(args[0]);
|
||||
ArrayBufferViewContents<uint8_t> buffer(args[0]);
|
||||
|
||||
uint32_t needle = args[1].As<Uint32>()->Value();
|
||||
int64_t offset_i64 = args[2].As<Integer>()->Value();
|
||||
bool is_forward = args[3]->IsTrue();
|
||||
|
||||
int64_t opt_offset =
|
||||
IndexOfOffset(buffer.length(), offset_i64, 1, is_forward);
|
||||
if (opt_offset <= -1 || buffer.length() == 0) {
|
||||
return args.GetReturnValue().Set(-1);
|
||||
}
|
||||
size_t offset = static_cast<size_t>(opt_offset);
|
||||
CHECK_LT(offset, buffer.length());
|
||||
|
||||
const void* ptr;
|
||||
if (is_forward) {
|
||||
ptr = memchr(buffer.data() + offset, needle, buffer.length() - offset);
|
||||
} else {
|
||||
ptr = node::stringsearch::MemrchrFill(buffer.data(), needle, offset + 1);
|
||||
}
|
||||
const char* ptr_char = static_cast<const char*>(ptr);
|
||||
args.GetReturnValue().Set(ptr ? static_cast<int>(ptr_char - buffer.data())
|
||||
: -1);
|
||||
args.GetReturnValue().Set(IndexOfNumber(
|
||||
buffer.data(), buffer.length(), needle, offset_i64, is_forward));
|
||||
}
|
||||
|
||||
int32_t FastIndexOfNumber(v8::Local<v8::Value>,
|
||||
const FastApiTypedArray<uint8_t>& buffer,
|
||||
uint32_t needle,
|
||||
int64_t offset_i64,
|
||||
bool is_forward) {
|
||||
uint8_t* buffer_data;
|
||||
CHECK(buffer.getStorageIfAligned(&buffer_data));
|
||||
return IndexOfNumber(
|
||||
buffer_data, buffer.length(), needle, offset_i64, is_forward);
|
||||
}
|
||||
|
||||
static v8::CFunction fast_index_of_number(
|
||||
v8::CFunction::Make(FastIndexOfNumber));
|
||||
|
||||
void Swap16(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
@@ -1431,7 +1451,11 @@ void Initialize(Local<Object> target,
|
||||
SetMethodNoSideEffect(context, target, "compareOffset", CompareOffset);
|
||||
SetMethod(context, target, "fill", Fill);
|
||||
SetMethodNoSideEffect(context, target, "indexOfBuffer", IndexOfBuffer);
|
||||
SetMethodNoSideEffect(context, target, "indexOfNumber", IndexOfNumber);
|
||||
SetFastMethodNoSideEffect(context,
|
||||
target,
|
||||
"indexOfNumber",
|
||||
SlowIndexOfNumber,
|
||||
&fast_index_of_number);
|
||||
SetMethodNoSideEffect(context, target, "indexOfString", IndexOfString);
|
||||
|
||||
SetMethod(context, target, "detachArrayBuffer", DetachArrayBuffer);
|
||||
@@ -1492,7 +1516,9 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
||||
registry->Register(CompareOffset);
|
||||
registry->Register(Fill);
|
||||
registry->Register(IndexOfBuffer);
|
||||
registry->Register(IndexOfNumber);
|
||||
registry->Register(SlowIndexOfNumber);
|
||||
registry->Register(FastIndexOfNumber);
|
||||
registry->Register(fast_index_of_number.GetTypeInfo());
|
||||
registry->Register(IndexOfString);
|
||||
|
||||
registry->Register(Swap16);
|
||||
|
||||
@@ -41,6 +41,12 @@ using CFunctionCallbackWithTwoUint8ArraysFallback =
|
||||
const v8::FastApiTypedArray<uint8_t>&,
|
||||
const v8::FastApiTypedArray<uint8_t>&,
|
||||
v8::FastApiCallbackOptions&);
|
||||
using CFunctionCallbackWithUint8ArrayUint32Int64Bool =
|
||||
int32_t (*)(v8::Local<v8::Value>,
|
||||
const v8::FastApiTypedArray<uint8_t>&,
|
||||
uint32_t,
|
||||
int64_t,
|
||||
bool);
|
||||
using CFunctionWithUint32 = uint32_t (*)(v8::Local<v8::Value>,
|
||||
const uint32_t input);
|
||||
using CFunctionWithDoubleReturnDouble = double (*)(v8::Local<v8::Value>,
|
||||
@@ -68,6 +74,7 @@ class ExternalReferenceRegistry {
|
||||
V(CFunctionCallbackWithStrings) \
|
||||
V(CFunctionCallbackWithTwoUint8Arrays) \
|
||||
V(CFunctionCallbackWithTwoUint8ArraysFallback) \
|
||||
V(CFunctionCallbackWithUint8ArrayUint32Int64Bool) \
|
||||
V(CFunctionWithUint32) \
|
||||
V(CFunctionWithDoubleReturnDouble) \
|
||||
V(CFunctionWithInt64Fallback) \
|
||||
|
||||
Reference in new issue
Block a user