Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
buffer: add indexOf method
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
commit 4dedc0929472976e8730fd317b05a4eabf522f86
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)