diff options
author | James M Snell <jasnell@gmail.com> | 2016-03-24 00:27:39 +0300 |
---|---|---|
committer | James M Snell <jasnell@gmail.com> | 2016-04-09 06:16:46 +0300 |
commit | a2466896ddd0c89e80755a64acf0cac7e31e84e0 (patch) | |
tree | 0c2588c016e268d9199e62d2077d5e9393e44445 /src | |
parent | 820844d6732a471ff0bff5ff477dec70133bdd3d (diff) |
buffer: add Buffer.prototype.compare by offset
Adds additional `targetStart`, `targetEnd`, `sourceStart,
and `sourceEnd` arguments to `Buffer.prototype.compare`
to allow comparison of sub-ranges of two Buffers without
requiring Buffer.prototype.slice()
Fixes: https://github.com/nodejs/node/issues/521
PR-URL: https://github.com/nodejs/node/pull/5880
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/node_buffer.cc | 76 |
1 files changed, 60 insertions, 16 deletions
diff --git a/src/node_buffer.cc b/src/node_buffer.cc index ca901a10894..322cc5f57ce 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -870,6 +870,62 @@ void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) { args.GetReturnValue().Set(args[0].As<String>()->Utf8Length()); } +// Normalize val to be an integer in the range of [1, -1] since +// implementations of memcmp() can vary by platform. +static int normalizeCompareVal(int val, size_t a_length, size_t b_length) { + if (val == 0) { + if (a_length > b_length) + return 1; + else if (a_length < b_length) + return -1; + } else { + if (val > 0) + return 1; + else + return -1; + } + return val; +} + +void CompareOffset(const FunctionCallbackInfo<Value> &args) { + Environment* env = Environment::GetCurrent(args); + + THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); + THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]); + SPREAD_ARG(args[0], ts_obj); + SPREAD_ARG(args[1], target); + + size_t target_start; + size_t source_start; + size_t source_end; + size_t target_end; + + CHECK_NOT_OOB(ParseArrayIndex(args[2], 0, &target_start)); + CHECK_NOT_OOB(ParseArrayIndex(args[3], 0, &source_start)); + CHECK_NOT_OOB(ParseArrayIndex(args[4], target_length, &target_end)); + CHECK_NOT_OOB(ParseArrayIndex(args[5], ts_obj_length, &source_end)); + + if (source_start > ts_obj_length) + return env->ThrowRangeError("out of range index"); + if (target_start > target_length) + return env->ThrowRangeError("out of range index"); + + CHECK_LE(source_start, source_end); + CHECK_LE(target_start, target_end); + + size_t to_cmp = MIN(MIN(source_end - source_start, + target_end - target_start), + ts_obj_length - source_start); + + int val = normalizeCompareVal(to_cmp > 0 ? + memcmp(ts_obj_data + source_start, + target_data + target_start, + to_cmp) : 0, + source_end - source_start, + target_end - target_start); + + args.GetReturnValue().Set(val); +} void Compare(const FunctionCallbackInfo<Value> &args) { Environment* env = Environment::GetCurrent(args); @@ -881,22 +937,9 @@ void Compare(const FunctionCallbackInfo<Value> &args) { size_t cmp_length = MIN(obj_a_length, obj_b_length); - int val = cmp_length > 0 ? memcmp(obj_a_data, obj_b_data, cmp_length) : 0; - - // Normalize val to be an integer in the range of [1, -1] since - // implementations of memcmp() can vary by platform. - if (val == 0) { - if (obj_a_length > obj_b_length) - val = 1; - else if (obj_a_length < obj_b_length) - val = -1; - } else { - if (val > 0) - val = 1; - else - val = -1; - } - + int val = normalizeCompareVal(cmp_length > 0 ? + memcmp(obj_a_data, obj_b_data, cmp_length) : 0, + obj_a_length, obj_b_length); args.GetReturnValue().Set(val); } @@ -1172,6 +1215,7 @@ void Initialize(Local<Object> target, env->SetMethod(target, "byteLengthUtf8", ByteLengthUtf8); env->SetMethod(target, "compare", Compare); + env->SetMethod(target, "compareOffset", CompareOffset); env->SetMethod(target, "fill", Fill); env->SetMethod(target, "indexOfBuffer", IndexOfBuffer); env->SetMethod(target, "indexOfNumber", IndexOfNumber); |