Skip to content

Commit

Permalink
buffer: add indexOf method
Browse files Browse the repository at this point in the history
Adds a `.indexOf` method to `Buffer`, which borrows semantics from
both `Array.prototype.indexOf` and `String.prototype.indexOf`.

`Buffer.prototype.indexOf` can be invoked with a Buffer, a string
or a number as the needle.  If the needle a Buffer or string, it will
find the first occurrence of this sequence of bytes.  If the needle is
a number, it will find the first occurrence of this byte.

Reviewed-by: Sam Rijs <[email protected]>
Fixes: #95
PR-URL: #160
  • Loading branch information
srijs authored and algesten committed Dec 14, 2014
1 parent a60056d commit 4dedc09
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 0 deletions.
7 changes: 7 additions & 0 deletions doc/api/buffer.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,13 @@ buffer.
var b = new Buffer(50);
b.fill("h");

### buf.indexOf(value[, fromIndex])

* `value` Buffer or String or Number
* `fromIndex` Number, Optional, Default: 0

Finds the index within the buffer of the first occurrence of the specified value, starting the search at fromIndex. Returns -1 if the value is not found.

## buffer.INSPECT_MAX_BYTES

* Number, Default: 50
Expand Down
10 changes: 10 additions & 0 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,16 @@ Buffer.prototype.fill = function fill(val, start, end) {
return this;
};

Buffer.prototype.indexOf = function indexOf(needle, pos) {
if (typeof needle === 'number') {
needle = new Buffer([needle]);
} else if (typeof needle === 'string') {
needle = new Buffer(needle);
} else if (!(needle instanceof Buffer)) {
throw new TypeError('Argument must be a Buffer, number or string');
}
return internal.indexOf(this, needle, pos);
};

// XXX remove in v0.13
Buffer.prototype.get = util.deprecate(function get(offset) {
Expand Down
50 changes: 50 additions & 0 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <limits.h>

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

#define CHECK_NOT_OOB(r) \
do { \
Expand Down Expand Up @@ -585,6 +586,54 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
args.GetReturnValue().Set(val);
}

void IndexOf(const FunctionCallbackInfo<Value> &args) {
Local<Object> obj = args[0]->ToObject();
char* obj_data =
static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData());
int32_t obj_length = obj->GetIndexedPropertiesExternalArrayDataLength();

Local<Object> search = args[1]->ToObject();
char* search_data =
static_cast<char*>(search->GetIndexedPropertiesExternalArrayData());
int32_t search_length = search->GetIndexedPropertiesExternalArrayDataLength();

int32_t pos = args[2]->Int32Value();
int32_t start = MIN(MAX(pos, 0), obj_length);

if (search_length == 0) {
return args.GetReturnValue().Set(start);
}

while (search_length <= obj_length - start) {
// Search for the first byte of the needle.
char *chr = reinterpret_cast<char *>(
memchr(&obj_data[start], search_data[0], obj_length - start));
int32_t chrpos = (intptr_t)chr - (intptr_t)obj_data;
if (chr == NULL) {
// First byte not found, short circuit.
return args.GetReturnValue().Set(-1);
}
if (search_length == 1) {
// Nothing more to compare, we found it.
return args.GetReturnValue().Set(chrpos);
}
if (search_length > obj_length - chrpos) {
// Needle is longer than the rest of the haystack,
// no way it is contained in there.
return args.GetReturnValue().Set(-1);
}
int cmp = memcmp(&chr[1], &search_data[1], search_length - 1);
if (cmp == 0) {
// All bytes are equal, we found it.
return args.GetReturnValue().Set(chrpos);
}
// Advance start position for next iteration.
start = chrpos + 1;
}

return args.GetReturnValue().Set(-1);
}


// pass Buffer object to load prototype methods
void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
Expand Down Expand Up @@ -629,6 +678,7 @@ void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
env->SetMethod(internal, "byteLength", ByteLength);
env->SetMethod(internal, "compare", Compare);
env->SetMethod(internal, "fill", Fill);
env->SetMethod(internal, "indexOf", IndexOf);

env->SetMethod(internal, "readDoubleBE", ReadDoubleBE);
env->SetMethod(internal, "readDoubleLE", ReadDoubleLE);
Expand Down
10 changes: 10 additions & 0 deletions test/simple/test-buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1184,3 +1184,13 @@ assert.throws(function() {
var b = new Buffer(1);
b.equals('abc');
});

// IndexOf Tests
assert.equal(Buffer('abc').indexOf(''), 0)
assert.equal(Buffer('abc').indexOf('bd'), -1)
assert.equal(Buffer('abc').indexOf('bc'), 1)
assert.equal(Buffer('abc').indexOf(0x62), 1)
assert.equal(Buffer('abc').indexOf(Buffer('bc')), 1)
assert.equal(Buffer('abc').indexOf(Buffer([0x62,0x63])), 1)
assert.equal(Buffer('abc').indexOf('bc', 1), 1)
assert.equal(Buffer('abc').indexOf('bc', 2), -1)

0 comments on commit 4dedc09

Please sign in to comment.