Skip to content

Commit 67e1819

Browse files
umamialextrevnorris
authored andcommitted
buffer: add includes() for parity with TypedArray
Add Buffer#includes() by wrapping an indexOf and performing a strict equals check to -1. The includes method takes the search value, byteOffset, and encoding as arguments. The test is a modified version of the indexOf test. Fixes: #3552 PR-URL: #3567 Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 23e7703 commit 67e1819

3 files changed

Lines changed: 274 additions & 0 deletions

File tree

‎doc/api/buffer.markdown‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,19 @@ Strings are interpreted as UTF8. Buffers will use the entire buffer. So in order
291291
to compare a partial Buffer use [`Buffer#slice()`][]. Numbers can range from 0 to
292292
255.
293293

294+
### buf.includes(value[, byteOffset][, encoding])
295+
296+
*`value` String, Buffer or Number
297+
*`byteOffset` Number, Optional, Default: 0
298+
*`encoding` String, Optional, Default: 'utf8'
299+
300+
Operates similar to
301+
[Array#includes()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes).
302+
Accepts a String, Buffer or Number. Strings are interpreted as UTF8 unless
303+
overridden with the `encoding` argument. Buffers will use the entire buffer.
304+
So in order to compare a partial Buffer use `Buffer#slice()`. Numbers can range
305+
from 0 to 255.
306+
294307
### buf.length
295308

296309
* Number

‎lib/buffer.js‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,11 @@ Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) {
488488
};
489489

490490

491+
Buffer.prototype.includes=functionincludes(val,byteOffset,encoding){
492+
returnthis.indexOf(val,byteOffset,encoding)!==-1;
493+
};
494+
495+
491496
Buffer.prototype.fill=functionfill(val,start,end){
492497
start=start>>0;
493498
end=(end===undefined) ? this.length : end>>0;
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
'use strict';
2+
constcommon=require('../common');
3+
constassert=require('assert');
4+
5+
constBuffer=require('buffer').Buffer;
6+
7+
constb=newBuffer('abcdef');
8+
constbuf_a=newBuffer('a');
9+
constbuf_bc=newBuffer('bc');
10+
constbuf_f=newBuffer('f');
11+
constbuf_z=newBuffer('z');
12+
constbuf_empty=newBuffer('');
13+
14+
assert(b.includes('a'));
15+
assert(!b.includes('a',1));
16+
assert(!b.includes('a',-1));
17+
assert(!b.includes('a',-4));
18+
assert(b.includes('a',-b.length));
19+
assert(b.includes('a',NaN));
20+
assert(b.includes('a',-Infinity));
21+
assert(!b.includes('a',Infinity));
22+
assert(b.includes('bc'));
23+
assert(!b.includes('bc',2));
24+
assert(!b.includes('bc',-1));
25+
assert(!b.includes('bc',-3));
26+
assert(b.includes('bc',-5));
27+
assert(b.includes('bc',NaN));
28+
assert(b.includes('bc',-Infinity));
29+
assert(!b.includes('bc',Infinity));
30+
assert(b.includes('f'),b.length-1);
31+
assert(!b.includes('z'));
32+
assert(!b.includes(''));
33+
assert(!b.includes('',1));
34+
assert(!b.includes('',b.length+1));
35+
assert(!b.includes('',Infinity));
36+
assert(b.includes(buf_a));
37+
assert(!b.includes(buf_a,1));
38+
assert(!b.includes(buf_a,-1));
39+
assert(!b.includes(buf_a,-4));
40+
assert(b.includes(buf_a,-b.length));
41+
assert(b.includes(buf_a,NaN));
42+
assert(b.includes(buf_a,-Infinity));
43+
assert(!b.includes(buf_a,Infinity));
44+
assert(b.includes(buf_bc));
45+
assert(!b.includes(buf_bc,2));
46+
assert(!b.includes(buf_bc,-1));
47+
assert(!b.includes(buf_bc,-3));
48+
assert(b.includes(buf_bc,-5));
49+
assert(b.includes(buf_bc,NaN));
50+
assert(b.includes(buf_bc,-Infinity));
51+
assert(!b.includes(buf_bc,Infinity));
52+
assert(b.includes(buf_f),b.length-1);
53+
assert(!b.includes(buf_z));
54+
assert(!b.includes(buf_empty));
55+
assert(!b.includes(buf_empty,1));
56+
assert(!b.includes(buf_empty,b.length+1));
57+
assert(!b.includes(buf_empty,Infinity));
58+
assert(b.includes(0x61));
59+
assert(!b.includes(0x61,1));
60+
assert(!b.includes(0x61,-1));
61+
assert(!b.includes(0x61,-4));
62+
assert(b.includes(0x61,-b.length));
63+
assert(b.includes(0x61,NaN));
64+
assert(b.includes(0x61,-Infinity));
65+
assert(!b.includes(0x61,Infinity));
66+
assert(!b.includes(0x0));
67+
68+
// test offsets
69+
assert(b.includes('d',2));
70+
assert(b.includes('f',5));
71+
assert(b.includes('f',-1));
72+
assert(!b.includes('f',6));
73+
74+
assert(b.includes(Buffer('d'),2));
75+
assert(b.includes(Buffer('f'),5));
76+
assert(b.includes(Buffer('f'),-1));
77+
assert(!b.includes(Buffer('f'),6));
78+
79+
assert(!Buffer('ff').includes(Buffer('f'),1,'ucs2'));
80+
81+
// test hex encoding
82+
assert(
83+
Buffer(b.toString('hex'),'hex')
84+
.includes('64',0,'hex'));
85+
assert(
86+
Buffer(b.toString('hex'),'hex')
87+
.includes(Buffer('64','hex'),0,'hex'));
88+
89+
// test base64 encoding
90+
assert(
91+
Buffer(b.toString('base64'),'base64')
92+
.includes('ZA==',0,'base64'));
93+
assert(
94+
Buffer(b.toString('base64'),'base64')
95+
.includes(Buffer('ZA==','base64'),0,'base64'));
96+
97+
// test ascii encoding
98+
assert(
99+
Buffer(b.toString('ascii'),'ascii')
100+
.includes('d',0,'ascii'));
101+
assert(
102+
Buffer(b.toString('ascii'),'ascii')
103+
.includes(Buffer('d','ascii'),0,'ascii'));
104+
105+
// test binary encoding
106+
assert(
107+
Buffer(b.toString('binary'),'binary')
108+
.includes('d',0,'binary'));
109+
assert(
110+
Buffer(b.toString('binary'),'binary')
111+
.includes(Buffer('d','binary'),0,'binary'));
112+
113+
114+
// test usc2 encoding
115+
vartwoByteString=newBuffer('\u039a\u0391\u03a3\u03a3\u0395','ucs2');
116+
117+
assert(twoByteString.includes('\u0395',4,'ucs2'));
118+
assert(twoByteString.includes('\u03a3',-4,'ucs2'));
119+
assert(twoByteString.includes('\u03a3',-6,'ucs2'));
120+
assert(twoByteString.includes(
121+
newBuffer('\u03a3','ucs2'),-6,'ucs2'));
122+
assert(!twoByteString.includes('\u03a3',-2,'ucs2'));
123+
124+
constmixedByteStringUcs2=
125+
newBuffer('\u039a\u0391abc\u03a3\u03a3\u0395','ucs2');
126+
assert(mixedByteStringUcs2.includes('bc',0,'ucs2'));
127+
assert(mixedByteStringUcs2.includes('\u03a3',0,'ucs2'));
128+
assert(!mixedByteStringUcs2.includes('\u0396',0,'ucs2'));
129+
130+
assert(
131+
6,mixedByteStringUcs2.includes(newBuffer('bc','ucs2'),0,'ucs2'));
132+
assert(
133+
10,mixedByteStringUcs2.includes(newBuffer('\u03a3','ucs2'),0,'ucs2'));
134+
assert(
135+
-1,mixedByteStringUcs2.includes(newBuffer('\u0396','ucs2'),0,'ucs2'));
136+
137+
twoByteString=newBuffer('\u039a\u0391\u03a3\u03a3\u0395','ucs2');
138+
139+
// Test single char pattern
140+
assert(twoByteString.includes('\u039a',0,'ucs2'));
141+
assert(twoByteString.includes('\u0391',0,'ucs2'),'Alpha');
142+
assert(twoByteString.includes('\u03a3',0,'ucs2'),'First Sigma');
143+
assert(twoByteString.includes('\u03a3',6,'ucs2'),'Second Sigma');
144+
assert(twoByteString.includes('\u0395',0,'ucs2'),'Epsilon');
145+
assert(!twoByteString.includes('\u0392',0,'ucs2'),'Not beta');
146+
147+
// Test multi-char pattern
148+
assert(twoByteString.includes('\u039a\u0391',0,'ucs2'),'Lambda Alpha');
149+
assert(twoByteString.includes('\u0391\u03a3',0,'ucs2'),'Alpha Sigma');
150+
assert(twoByteString.includes('\u03a3\u03a3',0,'ucs2'),'Sigma Sigma');
151+
assert(twoByteString.includes('\u03a3\u0395',0,'ucs2'),'Sigma Epsilon');
152+
153+
constmixedByteStringUtf8=newBuffer('\u039a\u0391abc\u03a3\u03a3\u0395');
154+
assert(mixedByteStringUtf8.includes('bc'));
155+
assert(mixedByteStringUtf8.includes('bc',5));
156+
assert(mixedByteStringUtf8.includes('bc',-8));
157+
assert(mixedByteStringUtf8.includes('\u03a3'));
158+
assert(!mixedByteStringUtf8.includes('\u0396'));
159+
160+
161+
// Test complex string includes algorithms. Only trigger for long strings.
162+
// Long string that isn't a simple repeat of a shorter string.
163+
varlongString='A';
164+
for(vari=66;i<76;i++){// from 'B' to 'K'
165+
longString=longString+String.fromCharCode(i)+longString;
166+
}
167+
168+
constlongBufferString=newBuffer(longString);
169+
170+
// pattern of 15 chars, repeated every 16 chars in long
171+
varpattern='ABACABADABACABA';
172+
for(vari=0;i<longBufferString.length-pattern.length;i+=7){
173+
constincludes=longBufferString.includes(pattern,i);
174+
assert(includes,'Long ABACABA...-string at index '+i);
175+
}
176+
assert(longBufferString.includes('AJABACA'),'Long AJABACA, First J');
177+
assert(longBufferString.includes('AJABACA',511),'Long AJABACA, Second J');
178+
179+
pattern='JABACABADABACABA';
180+
assert(longBufferString.includes(pattern),'Long JABACABA..., First J');
181+
assert(longBufferString.includes(pattern,512),'Long JABACABA..., Second J');
182+
183+
// Search for a non-ASCII string in a pure ASCII string.
184+
constasciiString=newBuffer(
185+
'arglebargleglopglyfarglebargleglopglyfarglebargleglopglyf');
186+
assert(!asciiString.includes('\x2061'));
187+
assert(asciiString.includes('leb',0));
188+
189+
// Search in string containing many non-ASCII chars.
190+
constallCodePoints=[];
191+
for(vari=0;i<65536;i++)allCodePoints[i]=i;
192+
constallCharsString=String.fromCharCode.apply(String,allCodePoints);
193+
constallCharsBufferUtf8=newBuffer(allCharsString);
194+
constallCharsBufferUcs2=newBuffer(allCharsString,'ucs2');
195+
196+
// Search for string long enough to trigger complex search with ASCII pattern
197+
// and UC16 subject.
198+
assert(!allCharsBufferUtf8.includes('notfound'));
199+
assert(!allCharsBufferUcs2.includes('notfound'));
200+
201+
// Find substrings in Utf8.
202+
varlengths=[1,3,15];// Single char, simple and complex.
203+
varindices=[0x5,0x60,0x400,0x680,0x7ee,0xFF02,0x16610,0x2f77b];
204+
for(varlengthIndex=0;lengthIndex<lengths.length;lengthIndex++){
205+
for(vari=0;i<indices.length;i++){
206+
constindex=indices[i];
207+
varlength=lengths[lengthIndex];
208+
209+
if(index+length>0x7F){
210+
length=2*length;
211+
}
212+
213+
if(index+length>0x7FF){
214+
length=3*length;
215+
}
216+
217+
if(index+length>0xFFFF){
218+
length=4*length;
219+
}
220+
221+
constpatternBufferUtf8=allCharsBufferUtf8.slice(index,index+length);
222+
assert(index,allCharsBufferUtf8.includes(patternBufferUtf8));
223+
224+
constpatternStringUtf8=patternBufferUtf8.toString();
225+
assert(index,allCharsBufferUtf8.includes(patternStringUtf8));
226+
}
227+
}
228+
229+
// Find substrings in Usc2.
230+
lengths=[2,4,16];// Single char, simple and complex.
231+
indices=[0x5,0x65,0x105,0x205,0x285,0x2005,0x2085,0xfff0];
232+
for(varlengthIndex=0;lengthIndex<lengths.length;lengthIndex++){
233+
for(vari=0;i<indices.length;i++){
234+
constindex=indices[i]*2;
235+
varlength=lengths[lengthIndex];
236+
237+
constpatternBufferUcs2=
238+
allCharsBufferUcs2.slice(index,index+length);
239+
assert(
240+
index,allCharsBufferUcs2.includes(patternBufferUcs2,0,'ucs2'));
241+
242+
constpatternStringUcs2=patternBufferUcs2.toString('ucs2');
243+
assert(
244+
index,allCharsBufferUcs2.includes(patternStringUcs2,0,'ucs2'));
245+
}
246+
}
247+
248+
assert.throws(function(){
249+
b.includes(function(){});
250+
});
251+
assert.throws(function(){
252+
b.includes({});
253+
});
254+
assert.throws(function(){
255+
b.includes([]);
256+
});

0 commit comments

Comments
 (0)