|
34 | 34 | #include <limits.h> |
35 | 35 |
|
36 | 36 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
| 37 | +#define MAX(a, b) ((a) > (b) ? (a) : (b)) |
37 | 38 |
|
38 | 39 | #define CHECK_NOT_OOB(r) \ |
39 | 40 | do { \ |
@@ -585,6 +586,54 @@ void Compare(const FunctionCallbackInfo<Value> &args) { |
585 | 586 | args.GetReturnValue().Set(val); |
586 | 587 | } |
587 | 588 |
|
| 589 | +void IndexOf(const FunctionCallbackInfo<Value> &args) { |
| 590 | + Local<Object> obj = args[0]->ToObject(); |
| 591 | + char* obj_data = |
| 592 | + static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData()); |
| 593 | + int32_t obj_length = obj->GetIndexedPropertiesExternalArrayDataLength(); |
| 594 | + |
| 595 | + Local<Object> search = args[1]->ToObject(); |
| 596 | + char* search_data = |
| 597 | + static_cast<char*>(search->GetIndexedPropertiesExternalArrayData()); |
| 598 | + int32_t search_length = search->GetIndexedPropertiesExternalArrayDataLength(); |
| 599 | + |
| 600 | + int32_t pos = args[2]->Int32Value(); |
| 601 | + int32_t start = MIN(MAX(pos, 0), obj_length); |
| 602 | + |
| 603 | + if (search_length == 0) { |
| 604 | + return args.GetReturnValue().Set(start); |
| 605 | + } |
| 606 | + |
| 607 | + while (search_length <= obj_length - start) { |
| 608 | + // Search for the first byte of the needle. |
| 609 | + char *chr = reinterpret_cast<char *>( |
| 610 | + memchr(&obj_data[start], search_data[0], obj_length - start)); |
| 611 | + int32_t chrpos = (intptr_t)chr - (intptr_t)obj_data; |
| 612 | + if (chr == NULL) { |
| 613 | + // First byte not found, short circuit. |
| 614 | + return args.GetReturnValue().Set(-1); |
| 615 | + } |
| 616 | + if (search_length == 1) { |
| 617 | + // Nothing more to compare, we found it. |
| 618 | + return args.GetReturnValue().Set(chrpos); |
| 619 | + } |
| 620 | + if (search_length > obj_length - chrpos) { |
| 621 | + // Needle is longer than the rest of the haystack, |
| 622 | + // no way it is contained in there. |
| 623 | + return args.GetReturnValue().Set(-1); |
| 624 | + } |
| 625 | + int cmp = memcmp(&chr[1], &search_data[1], search_length - 1); |
| 626 | + if (cmp == 0) { |
| 627 | + // All bytes are equal, we found it. |
| 628 | + return args.GetReturnValue().Set(chrpos); |
| 629 | + } |
| 630 | + // Advance start position for next iteration. |
| 631 | + start = chrpos + 1; |
| 632 | + } |
| 633 | + |
| 634 | + return args.GetReturnValue().Set(-1); |
| 635 | +} |
| 636 | + |
588 | 637 |
|
589 | 638 | // pass Buffer object to load prototype methods |
590 | 639 | void SetupBufferJS(const FunctionCallbackInfo<Value>& args) { |
@@ -629,6 +678,7 @@ void SetupBufferJS(const FunctionCallbackInfo<Value>& args) { |
629 | 678 | env->SetMethod(internal, "byteLength", ByteLength); |
630 | 679 | env->SetMethod(internal, "compare", Compare); |
631 | 680 | env->SetMethod(internal, "fill", Fill); |
| 681 | + env->SetMethod(internal, "indexOf", IndexOf); |
632 | 682 |
|
633 | 683 | env->SetMethod(internal, "readDoubleBE", ReadDoubleBE); |
634 | 684 | env->SetMethod(internal, "readDoubleLE", ReadDoubleLE); |
|
0 commit comments