Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

indexOf empty string in buffer should return 0 #13023

Closed
simonkcleung opened this issue May 14, 2017 · 8 comments
Closed

indexOf empty string in buffer should return 0 #13023

simonkcleung opened this issue May 14, 2017 · 8 comments
Labels
buffer Issues and PRs related to the buffer subsystem.

Comments

@simonkcleung
Copy link

"abc".indexOf("") return 0.
But Buffer.from("abc").indexOf("") return -1.
Expected result : 0

@addaleax addaleax added the buffer Issues and PRs related to the buffer subsystem. label May 14, 2017
@lance
Copy link
Member

lance commented May 14, 2017

Hmm - the Buffer#indexOf documentation explicitly states that it will return -1 if the value is not found. https://nodejs.org/api/buffer.html#buffer_buf_indexof_value_byteoffset_encoding

Returns: The index of the first occurrence of value in buf or -1 if buf does not contain value

I believe this is expected behavior.

@TimothyGu TimothyGu added the question Issues that look for answers. label May 14, 2017
@TimothyGu
Copy link
Member

TimothyGu commented May 14, 2017

See what @addaleax said below!

The following information is wrong, see #13023 (comment)!

Buffer functions more akin to an array than a string. (In fact it extends the Uint8Array class!) ["a", "b", "c"].indexOf("") returns -1 also.

@addaleax
Copy link
Member

addaleax commented May 14, 2017

@lance I think this is a bug – it makes sense for an empty input value to say that it is found immediately, without any searching. Also, String.prototype.indexOf behaves the same way, and I think consistency is important (especially when there’s no reason to deviate) because developers expect them to behave the same way.

@TimothyGu Unlike Array#indexOf, Buffer#indexOf doesn’t compare elements – it compares subsequences, and there’s no equivalent of an empty subsequence for arrays. :)

This should be enough to fix:

diff
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index 367af6592ff3..32a942a42c4e 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -974,7 +974,13 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
   const size_t needle_length =
       StringBytes::Size(args.GetIsolate(), needle, enc);
 
-  if (needle_length == 0 || haystack_length == 0) {
+  if (needle_length == 0) {
+    const double first_index = is_forward ? 0 : haystack_length;
+    args.GetReturnValue().Set(first_index);
+    return;
+  }
+
+  if (haystack_length == 0) {
     return args.GetReturnValue().Set(-1);
   }
 
@@ -1077,7 +1083,13 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
   const char* needle = buf_data;
   const size_t needle_length = buf_length;
 
-  if (needle_length == 0 || haystack_length == 0) {
+  if (needle_length == 0) {
+    const double first_index = is_forward ? 0 : haystack_length;
+    args.GetReturnValue().Set(first_index);
+    return;
+  }
+
+  if (haystack_length == 0) {
     return args.GetReturnValue().Set(-1);
   }

@addaleax addaleax removed the question Issues that look for answers. label May 14, 2017
@TimothyGu
Copy link
Member

Oops, read what @addaleax said :)

@lance
Copy link
Member

lance commented May 14, 2017

@addaleax I see your point - especially given that String.prototype.indexOf works this way. Comment retracted. And your diff looks reasonable to me.

addaleax added a commit to addaleax/node that referenced this issue May 14, 2017
Make searches for empty subsequences do exactly what
`String.prototype.indexOf()` does.

Fixes: nodejs#13023
@simonkcleung
Copy link
Author

Welcome for the changes. But I would like to explain consistency more.
In doc:

Buffer class implements the Uint8Array API in a manner that is more optimized and suitable for Node.js' use cases

There is no consistency in the first place. Buffer.from("abc").indexOf("") = -1, is more consistent with the Uint8Array API.

However, existing Buffer#indexOf implements the String#indexOf more likely. Especially when Buffer.from("abc").indexOf("bc") = 1. Then, Buffer.from("abc").indexOf("") should be 0.

@joyeecheung
Copy link
Member

joyeecheung commented May 17, 2017

Hmm, since the spec has already defined TypedArray.prototype.indexOf() as:

22.2.3.14%TypedArray%.prototype.indexOf ( searchElement [ , fromIndex ] )
%TypedArray%.prototype.indexOf is a distinct function that implements the same algorithm as Array.prototype.indexOf as defined in 22.1.3.12 except that the this object's [[ArrayLength]] internal slot is accessed in place of performing a [[Get]] of "length"

I would say the current behavior is more consistent..especially when we are on our way making APIs that accept Buffers also accept Uint8Arrays

@addaleax
Copy link
Member

@joyeecheung That’s what Uint8Array.prototype.indexOf does, but as mentioned above we already deviate very strongly from that – we accept sequences instead of individual values as input, and there’s no way of mapping that to Uint8Array.prototype.indexOf’s type signature.

anchnk pushed a commit to anchnk/node that referenced this issue May 19, 2017
Make searches for empty subsequences do exactly what
`String.prototype.indexOf()` does.

Fixes: nodejs#13023
PR-URL: nodejs#13024
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
buffer Issues and PRs related to the buffer subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants