faec886660dc15748403aaf86644ceefef7fa7fe
[folly.git] / folly / test / RangeTest.cpp
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // @author Kristina Holst (kholst@fb.com)
18 // @author Andrei Alexandrescu (andrei.alexandrescu@fb.com)
19
20 #include "folly/Range.h"
21
22 #include <limits>
23 #include <cstdlib>
24 #include <string>
25 #include <iterator>
26 #include <sys/mman.h>
27 #include <boost/range/concepts.hpp>
28 #include <gtest/gtest.h>
29
30 namespace folly { namespace detail {
31
32 // declaration of functions in Range.cpp
33 size_t qfind_first_byte_of_memchr(const StringPiece& haystack,
34                                   const StringPiece& needles);
35
36 size_t qfind_first_byte_of_byteset(const StringPiece& haystack,
37                                    const StringPiece& needles);
38
39 }}  // namespaces
40
41 using namespace folly;
42 using namespace std;
43
44 BOOST_CONCEPT_ASSERT((boost::RandomAccessRangeConcept<StringPiece>));
45
46 TEST(StringPiece, All) {
47   const char* foo = "foo";
48   const char* foo2 = "foo";
49   string fooStr(foo);
50   string foo2Str(foo2);
51
52   // we expect the compiler to optimize things so that there's only one copy
53   // of the string literal "foo", even though we've got it in multiple places
54   EXPECT_EQ(foo, foo2);  // remember, this uses ==, not strcmp, so it's a ptr
55                          // comparison rather than lexical
56
57   // the string object creates copies though, so the c_str of these should be
58   // distinct
59   EXPECT_NE(fooStr.c_str(), foo2Str.c_str());
60
61   // test the basic StringPiece functionality
62   StringPiece s(foo);
63   EXPECT_EQ(s.size(), 3);
64
65   EXPECT_EQ(s.start(), foo);              // ptr comparison
66   EXPECT_NE(s.start(), fooStr.c_str());   // ptr comparison
67   EXPECT_NE(s.start(), foo2Str.c_str());  // ptr comparison
68
69   EXPECT_EQ(s.toString(), foo);              // lexical comparison
70   EXPECT_EQ(s.toString(), fooStr.c_str());   // lexical comparison
71   EXPECT_EQ(s.toString(), foo2Str.c_str());  // lexical comparison
72
73   EXPECT_EQ(s, foo);                      // lexical comparison
74   EXPECT_EQ(s, fooStr);                   // lexical comparison
75   EXPECT_EQ(s, foo2Str);                  // lexical comparison
76   EXPECT_EQ(foo, s);
77
78   // check using StringPiece to reference substrings
79   const char* foobarbaz = "foobarbaz";
80
81   // the full "foobarbaz"
82   s.reset(foobarbaz, strlen(foobarbaz));
83   EXPECT_EQ(s.size(), 9);
84   EXPECT_EQ(s.start(), foobarbaz);
85   EXPECT_EQ(s, "foobarbaz");
86
87   // only the 'foo'
88   s.assign(foobarbaz, foobarbaz + 3);
89   EXPECT_EQ(s.size(), 3);
90   EXPECT_EQ(s.start(), foobarbaz);
91   EXPECT_EQ(s, "foo");
92
93   // find
94   s.reset(foobarbaz, strlen(foobarbaz));
95   EXPECT_EQ(s.find("bar"), 3);
96   EXPECT_EQ(s.find("ba", 3), 3);
97   EXPECT_EQ(s.find("ba", 4), 6);
98   EXPECT_EQ(s.find("notfound"), StringPiece::npos);
99   EXPECT_EQ(s.find("notfound", 1), StringPiece::npos);
100   EXPECT_EQ(s.find("bar", 4), StringPiece::npos);  // starting position too far
101   // starting pos that is obviously past the end -- This works for std::string
102   EXPECT_EQ(s.toString().find("notfound", 55), StringPiece::npos);
103   EXPECT_EQ(s.find("z", s.size()), StringPiece::npos);
104   EXPECT_EQ(s.find("z", 55), StringPiece::npos);
105   // empty needle
106   EXPECT_EQ(s.find(""), std::string().find(""));
107   EXPECT_EQ(s.find(""), 0);
108
109   // single char finds
110   EXPECT_EQ(s.find('b'), 3);
111   EXPECT_EQ(s.find('b', 3), 3);
112   EXPECT_EQ(s.find('b', 4), 6);
113   EXPECT_EQ(s.find('o', 2), 2);
114   EXPECT_EQ(s.find('y'), StringPiece::npos);
115   EXPECT_EQ(s.find('y', 1), StringPiece::npos);
116   EXPECT_EQ(s.find('o', 4), StringPiece::npos);  // starting position too far
117   // starting pos that is obviously past the end -- This works for std::string
118   EXPECT_EQ(s.toString().find('y', 55), StringPiece::npos);
119   EXPECT_EQ(s.find('z', s.size()), StringPiece::npos);
120   EXPECT_EQ(s.find('z', 55), StringPiece::npos);
121   // null char
122   EXPECT_EQ(s.find('\0'), std::string().find('\0'));
123   EXPECT_EQ(s.find('\0'), StringPiece::npos);
124
125   // single char rfinds
126   EXPECT_EQ(s.rfind('b'), 6);
127   EXPECT_EQ(s.rfind('y'), StringPiece::npos);
128   EXPECT_EQ(s.str().rfind('y'), StringPiece::npos);
129   EXPECT_EQ(ByteRange(s).rfind('b'), 6);
130   EXPECT_EQ(ByteRange(s).rfind('y'), StringPiece::npos);
131   // null char
132   EXPECT_EQ(s.rfind('\0'), s.str().rfind('\0'));
133   EXPECT_EQ(s.rfind('\0'), StringPiece::npos);
134
135   // find_first_of
136   s.reset(foobarbaz, strlen(foobarbaz));
137   EXPECT_EQ(s.find_first_of("bar"), 3);
138   EXPECT_EQ(s.find_first_of("ba", 3), 3);
139   EXPECT_EQ(s.find_first_of("ba", 4), 4);
140   EXPECT_EQ(s.find_first_of("xyxy"), StringPiece::npos);
141   EXPECT_EQ(s.find_first_of("xyxy", 1), StringPiece::npos);
142   // starting position too far
143   EXPECT_EQ(s.find_first_of("foo", 4), StringPiece::npos);
144   // starting pos that is obviously past the end -- This works for std::string
145   EXPECT_EQ(s.toString().find_first_of("xyxy", 55), StringPiece::npos);
146   EXPECT_EQ(s.find_first_of("z", s.size()), StringPiece::npos);
147   EXPECT_EQ(s.find_first_of("z", 55), StringPiece::npos);
148   // empty needle. Note that this returns npos, while find() returns 0!
149   EXPECT_EQ(s.find_first_of(""), std::string().find_first_of(""));
150   EXPECT_EQ(s.find_first_of(""), StringPiece::npos);
151
152   // single char find_first_ofs
153   EXPECT_EQ(s.find_first_of('b'), 3);
154   EXPECT_EQ(s.find_first_of('b', 3), 3);
155   EXPECT_EQ(s.find_first_of('b', 4), 6);
156   EXPECT_EQ(s.find_first_of('o', 2), 2);
157   EXPECT_EQ(s.find_first_of('y'), StringPiece::npos);
158   EXPECT_EQ(s.find_first_of('y', 1), StringPiece::npos);
159   // starting position too far
160   EXPECT_EQ(s.find_first_of('o', 4), StringPiece::npos);
161   // starting pos that is obviously past the end -- This works for std::string
162   EXPECT_EQ(s.toString().find_first_of('y', 55), StringPiece::npos);
163   EXPECT_EQ(s.find_first_of('z', s.size()), StringPiece::npos);
164   EXPECT_EQ(s.find_first_of('z', 55), StringPiece::npos);
165   // null char
166   EXPECT_EQ(s.find_first_of('\0'), std::string().find_first_of('\0'));
167   EXPECT_EQ(s.find_first_of('\0'), StringPiece::npos);
168
169   // just "barbaz"
170   s.reset(foobarbaz + 3, strlen(foobarbaz + 3));
171   EXPECT_EQ(s.size(), 6);
172   EXPECT_EQ(s.start(), foobarbaz + 3);
173   EXPECT_EQ(s, "barbaz");
174
175   // just "bar"
176   s.reset(foobarbaz + 3, 3);
177   EXPECT_EQ(s.size(), 3);
178   EXPECT_EQ(s, "bar");
179
180   // clear
181   s.clear();
182   EXPECT_EQ(s.toString(), "");
183
184   // test an empty StringPiece
185   StringPiece s2;
186   EXPECT_EQ(s2.size(), 0);
187
188   // Test comparison operators
189   foo = "";
190   EXPECT_LE(s, foo);
191   EXPECT_LE(foo, s);
192   EXPECT_GE(s, foo);
193   EXPECT_GE(foo, s);
194   EXPECT_EQ(s, foo);
195   EXPECT_EQ(foo, s);
196
197   foo = "abc";
198   EXPECT_LE(s, foo);
199   EXPECT_LT(s, foo);
200   EXPECT_GE(foo, s);
201   EXPECT_GT(foo, s);
202   EXPECT_NE(s, foo);
203
204   EXPECT_LE(s, s);
205   EXPECT_LE(s, s);
206   EXPECT_GE(s, s);
207   EXPECT_GE(s, s);
208   EXPECT_EQ(s, s);
209   EXPECT_EQ(s, s);
210
211   s = "abc";
212   s2 = "abc";
213   EXPECT_LE(s, s2);
214   EXPECT_LE(s2, s);
215   EXPECT_GE(s, s2);
216   EXPECT_GE(s2, s);
217   EXPECT_EQ(s, s2);
218   EXPECT_EQ(s2, s);
219 }
220
221 template <class T>
222 void expectLT(const T& a, const T& b) {
223   EXPECT_TRUE(a < b);
224   EXPECT_TRUE(a <= b);
225   EXPECT_FALSE(a == b);
226   EXPECT_FALSE(a >= b);
227   EXPECT_FALSE(a > b);
228
229   EXPECT_FALSE(b < a);
230   EXPECT_FALSE(b <= a);
231   EXPECT_TRUE(b >= a);
232   EXPECT_TRUE(b > a);
233 }
234
235 template <class T>
236 void expectEQ(const T& a, const T& b) {
237   EXPECT_FALSE(a < b);
238   EXPECT_TRUE(a <= b);
239   EXPECT_TRUE(a == b);
240   EXPECT_TRUE(a >= b);
241   EXPECT_FALSE(a > b);
242 }
243
244 TEST(StringPiece, EightBitComparisons) {
245   char values[] = {'\x00', '\x20', '\x40', '\x7f', '\x80', '\xc0', '\xff'};
246   constexpr size_t count = sizeof(values) / sizeof(values[0]);
247   for (size_t i = 0; i < count; ++i) {
248     std::string a(1, values[i]);
249     // Defeat copy-on-write
250     std::string aCopy(a.data(), a.size());
251     expectEQ(a, aCopy);
252     expectEQ(StringPiece(a), StringPiece(aCopy));
253
254     for (size_t j = i + 1; j < count; ++j) {
255       std::string b(1, values[j]);
256       expectLT(a, b);
257       expectLT(StringPiece(a), StringPiece(b));
258     }
259   }
260 }
261
262 TEST(StringPiece, ToByteRange) {
263   StringPiece a("hello");
264   ByteRange b(a);
265   EXPECT_EQ(static_cast<const void*>(a.begin()),
266             static_cast<const void*>(b.begin()));
267   EXPECT_EQ(static_cast<const void*>(a.end()),
268             static_cast<const void*>(b.end()));
269
270   // and convert back again
271   StringPiece c(b);
272   EXPECT_EQ(a.begin(), c.begin());
273   EXPECT_EQ(a.end(), c.end());
274 }
275
276 TEST(StringPiece, InvalidRange) {
277   StringPiece a("hello");
278   EXPECT_EQ(a, a.subpiece(0, 10));
279   EXPECT_EQ(StringPiece("ello"), a.subpiece(1));
280   EXPECT_EQ(StringPiece("ello"), a.subpiece(1, std::string::npos));
281   EXPECT_EQ(StringPiece("ell"), a.subpiece(1, 3));
282   EXPECT_THROW(a.subpiece(6, 7), std::out_of_range);
283   EXPECT_THROW(a.subpiece(6), std::out_of_range);
284
285   std::string b("hello");
286   EXPECT_EQ(a, StringPiece(b, 0, 10));
287   EXPECT_EQ("ello", a.subpiece(1));
288   EXPECT_EQ("ello", a.subpiece(1, std::string::npos));
289   EXPECT_EQ("ell", a.subpiece(1, 3));
290   EXPECT_THROW(a.subpiece(6, 7), std::out_of_range);
291   EXPECT_THROW(a.subpiece(6), std::out_of_range);
292 }
293
294 #if FOLLY_HAVE_CONSTEXPR_STRLEN
295 constexpr char helloArray[] = "hello";
296
297 TEST(StringPiece, Constexpr) {
298   constexpr StringPiece hello1("hello");
299   EXPECT_EQ("hello", hello1);
300
301   constexpr StringPiece hello2(helloArray);
302   EXPECT_EQ("hello", hello2);
303 }
304 #endif
305
306 TEST(StringPiece, Prefix) {
307   StringPiece a("hello");
308   EXPECT_TRUE(a.startsWith(""));
309   EXPECT_TRUE(a.startsWith("h"));
310   EXPECT_TRUE(a.startsWith('h'));
311   EXPECT_TRUE(a.startsWith("hello"));
312   EXPECT_FALSE(a.startsWith("hellox"));
313   EXPECT_FALSE(a.startsWith('x'));
314   EXPECT_FALSE(a.startsWith("x"));
315
316   {
317     auto b = a;
318     EXPECT_TRUE(b.removePrefix(""));
319     EXPECT_EQ("hello", b);
320   }
321   {
322     auto b = a;
323     EXPECT_TRUE(b.removePrefix("h"));
324     EXPECT_EQ("ello", b);
325   }
326   {
327     auto b = a;
328     EXPECT_TRUE(b.removePrefix('h'));
329     EXPECT_EQ("ello", b);
330   }
331   {
332     auto b = a;
333     EXPECT_TRUE(b.removePrefix("hello"));
334     EXPECT_EQ("", b);
335   }
336   {
337     auto b = a;
338     EXPECT_FALSE(b.removePrefix("hellox"));
339     EXPECT_EQ("hello", b);
340   }
341   {
342     auto b = a;
343     EXPECT_FALSE(b.removePrefix("x"));
344     EXPECT_EQ("hello", b);
345   }
346   {
347     auto b = a;
348     EXPECT_FALSE(b.removePrefix('x'));
349     EXPECT_EQ("hello", b);
350   }
351 }
352
353 TEST(StringPiece, Suffix) {
354   StringPiece a("hello");
355   EXPECT_TRUE(a.endsWith(""));
356   EXPECT_TRUE(a.endsWith("o"));
357   EXPECT_TRUE(a.endsWith('o'));
358   EXPECT_TRUE(a.endsWith("hello"));
359   EXPECT_FALSE(a.endsWith("xhello"));
360   EXPECT_FALSE(a.endsWith("x"));
361   EXPECT_FALSE(a.endsWith('x'));
362
363   {
364     auto b = a;
365     EXPECT_TRUE(b.removeSuffix(""));
366     EXPECT_EQ("hello", b);
367   }
368   {
369     auto b = a;
370     EXPECT_TRUE(b.removeSuffix("o"));
371     EXPECT_EQ("hell", b);
372   }
373   {
374     auto b = a;
375     EXPECT_TRUE(b.removeSuffix('o'));
376     EXPECT_EQ("hell", b);
377   }
378   {
379     auto b = a;
380     EXPECT_TRUE(b.removeSuffix("hello"));
381     EXPECT_EQ("", b);
382   }
383   {
384     auto b = a;
385     EXPECT_FALSE(b.removeSuffix("xhello"));
386     EXPECT_EQ("hello", b);
387   }
388   {
389     auto b = a;
390     EXPECT_FALSE(b.removeSuffix("x"));
391     EXPECT_EQ("hello", b);
392   }
393   {
394     auto b = a;
395     EXPECT_FALSE(b.removeSuffix('x'));
396     EXPECT_EQ("hello", b);
397   }
398 }
399
400 TEST(StringPiece, PrefixEmpty) {
401   StringPiece a;
402   EXPECT_TRUE(a.startsWith(""));
403   EXPECT_FALSE(a.startsWith("a"));
404   EXPECT_FALSE(a.startsWith('a'));
405   EXPECT_TRUE(a.removePrefix(""));
406   EXPECT_EQ("", a);
407   EXPECT_FALSE(a.removePrefix("a"));
408   EXPECT_EQ("", a);
409   EXPECT_FALSE(a.removePrefix('a'));
410   EXPECT_EQ("", a);
411 }
412
413 TEST(StringPiece, SuffixEmpty) {
414   StringPiece a;
415   EXPECT_TRUE(a.endsWith(""));
416   EXPECT_FALSE(a.endsWith("a"));
417   EXPECT_FALSE(a.endsWith('a'));
418   EXPECT_TRUE(a.removeSuffix(""));
419   EXPECT_EQ("", a);
420   EXPECT_FALSE(a.removeSuffix("a"));
421   EXPECT_EQ("", a);
422   EXPECT_FALSE(a.removeSuffix('a'));
423   EXPECT_EQ("", a);
424 }
425
426 TEST(StringPiece, split_step_char_delimiter) {
427   //              0         1         2
428   //              012345678901234567890123456
429   auto const s = "this is just  a test string";
430   auto const e = std::next(s, std::strlen(s));
431   EXPECT_EQ('\0', *e);
432
433   folly::StringPiece p(s);
434   EXPECT_EQ(s, p.begin());
435   EXPECT_EQ(e, p.end());
436
437   auto x = p.split_step(' ');
438   EXPECT_EQ(std::next(s, 5), p.begin());
439   EXPECT_EQ(e, p.end());
440   EXPECT_EQ("this", x);
441
442   x = p.split_step(' ');
443   EXPECT_EQ(std::next(s, 8), p.begin());
444   EXPECT_EQ(e, p.end());
445   EXPECT_EQ("is", x);
446
447   x = p.split_step('u');
448   EXPECT_EQ(std::next(s, 10), p.begin());
449   EXPECT_EQ(e, p.end());
450   EXPECT_EQ("j", x);
451
452   x = p.split_step(' ');
453   EXPECT_EQ(std::next(s, 13), p.begin());
454   EXPECT_EQ(e, p.end());
455   EXPECT_EQ("st", x);
456
457   x = p.split_step(' ');
458   EXPECT_EQ(std::next(s, 14), p.begin());
459   EXPECT_EQ(e, p.end());
460   EXPECT_EQ("", x);
461
462   x = p.split_step(' ');
463   EXPECT_EQ(std::next(s, 16), p.begin());
464   EXPECT_EQ(e, p.end());
465   EXPECT_EQ("a", x);
466
467   x = p.split_step(' ');
468   EXPECT_EQ(std::next(s, 21), p.begin());
469   EXPECT_EQ(e, p.end());
470   EXPECT_EQ("test", x);
471
472   x = p.split_step(' ');
473   EXPECT_EQ(e, p.begin());
474   EXPECT_EQ(e, p.end());
475   EXPECT_EQ("string", x);
476
477   x = p.split_step(' ');
478   EXPECT_EQ(e, p.begin());
479   EXPECT_EQ(e, p.end());
480   EXPECT_EQ("", x);
481 }
482
483 TEST(StringPiece, split_step_range_delimiter) {
484   //              0         1         2         3
485   //              0123456789012345678901234567890123
486   auto const s = "this  is  just    a   test  string";
487   auto const e = std::next(s, std::strlen(s));
488   EXPECT_EQ('\0', *e);
489
490   folly::StringPiece p(s);
491   EXPECT_EQ(s, p.begin());
492   EXPECT_EQ(e, p.end());
493
494   auto x = p.split_step("  ");
495   EXPECT_EQ(std::next(s, 6), p.begin());
496   EXPECT_EQ(e, p.end());
497   EXPECT_EQ("this", x);
498
499   x = p.split_step("  ");
500   EXPECT_EQ(std::next(s, 10), p.begin());
501   EXPECT_EQ(e, p.end());
502   EXPECT_EQ("is", x);
503
504   x = p.split_step("u");
505   EXPECT_EQ(std::next(s, 12), p.begin());
506   EXPECT_EQ(e, p.end());
507   EXPECT_EQ("j", x);
508
509   x = p.split_step("  ");
510   EXPECT_EQ(std::next(s, 16), p.begin());
511   EXPECT_EQ(e, p.end());
512   EXPECT_EQ("st", x);
513
514   x = p.split_step("  ");
515   EXPECT_EQ(std::next(s, 18), p.begin());
516   EXPECT_EQ(e, p.end());
517   EXPECT_EQ("", x);
518
519   x = p.split_step("  ");
520   EXPECT_EQ(std::next(s, 21), p.begin());
521   EXPECT_EQ(e, p.end());
522   EXPECT_EQ("a", x);
523
524   x = p.split_step("  ");
525   EXPECT_EQ(std::next(s, 28), p.begin());
526   EXPECT_EQ(e, p.end());
527   EXPECT_EQ(" test", x);
528
529   x = p.split_step("  ");
530   EXPECT_EQ(e, p.begin());
531   EXPECT_EQ(e, p.end());
532   EXPECT_EQ("string", x);
533
534   x = p.split_step("  ");
535   EXPECT_EQ(e, p.begin());
536   EXPECT_EQ(e, p.end());
537   EXPECT_EQ("", x);
538
539   x = p.split_step(" ");
540   EXPECT_EQ(e, p.begin());
541   EXPECT_EQ(e, p.end());
542   EXPECT_EQ("", x);
543 }
544
545 void split_step_with_process_noop(folly::StringPiece) {}
546
547 TEST(StringPiece, split_step_with_process_char_delimiter) {
548   //              0         1         2
549   //              012345678901234567890123456
550   auto const s = "this is just  a test string";
551   auto const e = std::next(s, std::strlen(s));
552   EXPECT_EQ('\0', *e);
553
554   folly::StringPiece p(s);
555   EXPECT_EQ(s, p.begin());
556   EXPECT_EQ(e, p.end());
557
558   EXPECT_EQ(1, (p.split_step(' ', [&](folly::StringPiece x) {
559     EXPECT_EQ(std::next(s, 5), p.begin());
560     EXPECT_EQ(e, p.end());
561     EXPECT_EQ("this", x);
562     return 1;
563   })));
564
565   EXPECT_EQ(2, (p.split_step(' ', [&](folly::StringPiece x) {
566     EXPECT_EQ(std::next(s, 8), p.begin());
567     EXPECT_EQ(e, p.end());
568     EXPECT_EQ("is", x);
569     return 2;
570   })));
571
572   EXPECT_EQ(3, (p.split_step('u', [&](folly::StringPiece x) {
573     EXPECT_EQ(std::next(s, 10), p.begin());
574     EXPECT_EQ(e, p.end());
575     EXPECT_EQ("j", x);
576     return 3;
577   })));
578
579   EXPECT_EQ(4, (p.split_step(' ', [&](folly::StringPiece x) {
580     EXPECT_EQ(std::next(s, 13), p.begin());
581     EXPECT_EQ(e, p.end());
582     EXPECT_EQ("st", x);
583     return 4;
584   })));
585
586   EXPECT_EQ(5, (p.split_step(' ', [&](folly::StringPiece x) {
587     EXPECT_EQ(std::next(s, 14), p.begin());
588     EXPECT_EQ(e, p.end());
589     EXPECT_EQ("", x);
590     return 5;
591   })));
592
593   EXPECT_EQ(6, (p.split_step(' ', [&](folly::StringPiece x) {
594     EXPECT_EQ(std::next(s, 16), p.begin());
595     EXPECT_EQ(e, p.end());
596     EXPECT_EQ("a", x);
597     return 6;
598   })));
599
600   EXPECT_EQ(7, (p.split_step(' ', [&](folly::StringPiece x) {
601     EXPECT_EQ(std::next(s, 21), p.begin());
602     EXPECT_EQ(e, p.end());
603     EXPECT_EQ("test", x);
604     return 7;
605   })));
606
607   EXPECT_EQ(8, (p.split_step(' ', [&](folly::StringPiece x) {
608     EXPECT_EQ(e, p.begin());
609     EXPECT_EQ(e, p.end());
610     EXPECT_EQ("string", x);
611     return 8;
612   })));
613
614   EXPECT_EQ(9, (p.split_step(' ', [&](folly::StringPiece x) {
615     EXPECT_EQ(e, p.begin());
616     EXPECT_EQ(e, p.end());
617     EXPECT_EQ("", x);
618     return 9;
619   })));
620
621   EXPECT_TRUE((std::is_same<
622     void,
623     decltype(p.split_step(' ', split_step_with_process_noop))
624   >::value));
625
626   EXPECT_NO_THROW(p.split_step(' ', split_step_with_process_noop));
627 }
628
629 TEST(StringPiece, split_step_with_process_range_delimiter) {
630   //              0         1         2         3
631   //              0123456789012345678901234567890123
632   auto const s = "this  is  just    a   test  string";
633   auto const e = std::next(s, std::strlen(s));
634   EXPECT_EQ('\0', *e);
635
636   folly::StringPiece p(s);
637   EXPECT_EQ(s, p.begin());
638   EXPECT_EQ(e, p.end());
639
640   EXPECT_EQ(1, (p.split_step("  ", [&](folly::StringPiece x) {
641     EXPECT_EQ(std::next(s, 6), p.begin());
642     EXPECT_EQ(e, p.end());
643     EXPECT_EQ("this", x);
644     return 1;
645   })));
646
647   EXPECT_EQ(2, (p.split_step("  ", [&](folly::StringPiece x) {
648     EXPECT_EQ(std::next(s, 10), p.begin());
649     EXPECT_EQ(e, p.end());
650     EXPECT_EQ("is", x);
651     return 2;
652   })));
653
654   EXPECT_EQ(3, (p.split_step("u", [&](folly::StringPiece x) {
655     EXPECT_EQ(std::next(s, 12), p.begin());
656     EXPECT_EQ(e, p.end());
657     EXPECT_EQ("j", x);
658     return 3;
659   })));
660
661   EXPECT_EQ(4, (p.split_step("  ", [&](folly::StringPiece x) {
662     EXPECT_EQ(std::next(s, 16), p.begin());
663     EXPECT_EQ(e, p.end());
664     EXPECT_EQ("st", x);
665     return 4;
666   })));
667
668   EXPECT_EQ(5, (p.split_step("  ", [&](folly::StringPiece x) {
669     EXPECT_EQ(std::next(s, 18), p.begin());
670     EXPECT_EQ(e, p.end());
671     EXPECT_EQ("", x);
672     return 5;
673   })));
674
675   EXPECT_EQ(6, (p.split_step("  ", [&](folly::StringPiece x) {
676     EXPECT_EQ(std::next(s, 21), p.begin());
677     EXPECT_EQ(e, p.end());
678     EXPECT_EQ("a", x);
679     return 6;
680   })));
681
682   EXPECT_EQ(7, (p.split_step("  ", [&](folly::StringPiece x) {
683     EXPECT_EQ(std::next(s, 28), p.begin());
684     EXPECT_EQ(e, p.end());
685     EXPECT_EQ(" test", x);
686     return 7;
687   })));
688
689   EXPECT_EQ(8, (p.split_step("  ", [&](folly::StringPiece x) {
690     EXPECT_EQ(e, p.begin());
691     EXPECT_EQ(e, p.end());
692     EXPECT_EQ("string", x);
693     return 8;
694   })));
695
696   EXPECT_EQ(9, (p.split_step("  ", [&](folly::StringPiece x) {
697     EXPECT_EQ(e, p.begin());
698     EXPECT_EQ(e, p.end());
699     EXPECT_EQ("", x);
700     return 9;
701   })));
702
703   EXPECT_EQ(10, (p.split_step("  ", [&](folly::StringPiece x) {
704     EXPECT_EQ(e, p.begin());
705     EXPECT_EQ(e, p.end());
706     EXPECT_EQ("", x);
707     return 10;
708   })));
709
710   EXPECT_TRUE((std::is_same<
711     void,
712     decltype(p.split_step(' ', split_step_with_process_noop))
713   >::value));
714
715   EXPECT_NO_THROW(p.split_step(' ', split_step_with_process_noop));
716 }
717
718 TEST(qfind, UInt32_Ranges) {
719   vector<uint32_t> a({1, 2, 3, 260, 5});
720   vector<uint32_t> b({2, 3, 4});
721
722   auto a_range = folly::Range<const uint32_t*>(&a[0], a.size());
723   auto b_range = folly::Range<const uint32_t*>(&b[0], b.size());
724
725   EXPECT_EQ(qfind(a_range, b_range), string::npos);
726
727   a[3] = 4;
728   EXPECT_EQ(qfind(a_range, b_range), 1);
729 }
730
731 template <typename NeedleFinder>
732 class NeedleFinderTest : public ::testing::Test {
733  public:
734   static size_t find_first_byte_of(StringPiece haystack, StringPiece needles) {
735     return NeedleFinder::find_first_byte_of(haystack, needles);
736   }
737 };
738
739 struct SseNeedleFinder {
740   static size_t find_first_byte_of(StringPiece haystack, StringPiece needles) {
741     // This will only use the SSE version if it is supported on this CPU
742     // (selected using ifunc).
743     return detail::qfind_first_byte_of(haystack, needles);
744   }
745 };
746
747 struct NoSseNeedleFinder {
748   static size_t find_first_byte_of(StringPiece haystack, StringPiece needles) {
749     return detail::qfind_first_byte_of_nosse(haystack, needles);
750   }
751 };
752
753 struct MemchrNeedleFinder {
754   static size_t find_first_byte_of(StringPiece haystack, StringPiece needles) {
755     return detail::qfind_first_byte_of_memchr(haystack, needles);
756   }
757 };
758
759 struct ByteSetNeedleFinder {
760   static size_t find_first_byte_of(StringPiece haystack, StringPiece needles) {
761     return detail::qfind_first_byte_of_byteset(haystack, needles);
762   }
763 };
764
765 typedef ::testing::Types<SseNeedleFinder, NoSseNeedleFinder, MemchrNeedleFinder,
766                          ByteSetNeedleFinder> NeedleFinders;
767 TYPED_TEST_CASE(NeedleFinderTest, NeedleFinders);
768
769 TYPED_TEST(NeedleFinderTest, Null) {
770   { // null characters in the string
771     string s(10, char(0));
772     s[5] = 'b';
773     string delims("abc");
774     EXPECT_EQ(5, this->find_first_byte_of(s, delims));
775   }
776   { // null characters in delim
777     string s("abc");
778     string delims(10, char(0));
779     delims[3] = 'c';
780     delims[7] = 'b';
781     EXPECT_EQ(1, this->find_first_byte_of(s, delims));
782   }
783   { // range not terminated by null character
784     string buf = "abcdefghijklmnopqrstuvwxyz";
785     StringPiece s(buf.data() + 5, 3);
786     StringPiece delims("z");
787     EXPECT_EQ(string::npos, this->find_first_byte_of(s, delims));
788   }
789 }
790
791 TYPED_TEST(NeedleFinderTest, DelimDuplicates) {
792   string delims(1000, 'b');
793   EXPECT_EQ(1, this->find_first_byte_of("abc", delims));
794   EXPECT_EQ(string::npos, this->find_first_byte_of("ac", delims));
795 }
796
797 TYPED_TEST(NeedleFinderTest, Empty) {
798   string a = "abc";
799   string b = "";
800   EXPECT_EQ(string::npos, this->find_first_byte_of(a, b));
801   EXPECT_EQ(string::npos, this->find_first_byte_of(b, a));
802   EXPECT_EQ(string::npos, this->find_first_byte_of(b, b));
803 }
804
805 TYPED_TEST(NeedleFinderTest, Unaligned) {
806   // works correctly even if input buffers are not 16-byte aligned
807   string s = "0123456789ABCDEFGH";
808   for (int i = 0; i < s.size(); ++i) {
809     StringPiece a(s.c_str() + i);
810     for (int j = 0; j < s.size(); ++j) {
811       StringPiece b(s.c_str() + j);
812       EXPECT_EQ((i > j) ? 0 : j - i, this->find_first_byte_of(a, b));
813     }
814   }
815 }
816
817 // for some algorithms (specifically those that create a set of needles),
818 // we check for the edge-case of _all_ possible needles being sought.
819 TYPED_TEST(NeedleFinderTest, Needles256) {
820   string needles;
821   const auto minValue = std::numeric_limits<StringPiece::value_type>::min();
822   const auto maxValue = std::numeric_limits<StringPiece::value_type>::max();
823   // make the size ~big to avoid any edge-case branches for tiny haystacks
824   const int haystackSize = 50;
825   for (int i = minValue; i <= maxValue; i++) {  // <=
826     needles.push_back(i);
827   }
828   EXPECT_EQ(StringPiece::npos, this->find_first_byte_of("", needles));
829   for (int i = minValue; i <= maxValue; i++) {
830     EXPECT_EQ(0, this->find_first_byte_of(string(haystackSize, i), needles));
831   }
832
833   needles.append("these are redundant characters");
834   EXPECT_EQ(StringPiece::npos, this->find_first_byte_of("", needles));
835   for (int i = minValue; i <= maxValue; i++) {
836     EXPECT_EQ(0, this->find_first_byte_of(string(haystackSize, i), needles));
837   }
838 }
839
840 TYPED_TEST(NeedleFinderTest, Base) {
841   for (int i = 0; i < 32; ++i) {
842     for (int j = 0; j < 32; ++j) {
843       string s = string(i, 'X') + "abca" + string(i, 'X');
844       string delims = string(j, 'Y') + "a" + string(j, 'Y');
845       EXPECT_EQ(i, this->find_first_byte_of(s, delims));
846     }
847   }
848 }
849
850 const size_t kPageSize = 4096;
851 // Updates contents so that any read accesses past the last byte will
852 // cause a SIGSEGV.  It accomplishes this by changing access to the page that
853 // begins immediately after the end of the contents (as allocators and mmap()
854 // all operate on page boundaries, this is a reasonable assumption).
855 // This function will also initialize buf, which caller must free().
856 void createProtectedBuf(StringPiece& contents, char** buf) {
857   ASSERT_LE(contents.size(), kPageSize);
858   const size_t kSuccess = 0;
859   if (kSuccess != posix_memalign((void**)buf, kPageSize, 4 * kPageSize)) {
860     ASSERT_FALSE(true);
861   }
862   mprotect(*buf + kPageSize, kPageSize, PROT_NONE);
863   size_t newBegin = kPageSize - contents.size();
864   memcpy(*buf + newBegin, contents.data(), contents.size());
865   contents.reset(*buf + newBegin, contents.size());
866 }
867
868 void freeProtectedBuf(char* buf) {
869   mprotect(buf + kPageSize, kPageSize, PROT_READ | PROT_WRITE);
870   free(buf);
871 }
872
873 TYPED_TEST(NeedleFinderTest, NoSegFault) {
874   const string base = string(32, 'a') + string("b");
875   const string delims = string(32, 'c') + string("b");
876   for (int i = 0; i <= 32; i++) {
877     for (int j = 0; j <= 33; j++) {
878       for (int shouldFind = 0; shouldFind <= 1; ++shouldFind) {
879         StringPiece s1(base);
880         s1.advance(i);
881         ASSERT_TRUE(!s1.empty());
882         if (!shouldFind) {
883           s1.pop_back();
884         }
885         StringPiece s2(delims);
886         s2.advance(j);
887         char* buf1;
888         char* buf2;
889         createProtectedBuf(s1, &buf1);
890         createProtectedBuf(s2, &buf2);
891         // printf("s1: '%s' (%ld) \ts2: '%s' (%ld)\n",
892         //        string(s1.data(), s1.size()).c_str(), s1.size(),
893         //        string(s2.data(), s2.size()).c_str(), s2.size());
894         auto r1 = this->find_first_byte_of(s1, s2);
895         auto f1 = std::find_first_of(s1.begin(), s1.end(),
896                                      s2.begin(), s2.end());
897         auto e1 = (f1 == s1.end()) ? StringPiece::npos : f1 - s1.begin();
898         EXPECT_EQ(r1, e1);
899         auto r2 = this->find_first_byte_of(s2, s1);
900         auto f2 = std::find_first_of(s2.begin(), s2.end(),
901                                      s1.begin(), s1.end());
902         auto e2 = (f2 == s2.end()) ? StringPiece::npos : f2 - s2.begin();
903         EXPECT_EQ(r2, e2);
904         freeProtectedBuf(buf1);
905         freeProtectedBuf(buf2);
906       }
907     }
908   }
909 }
910
911 TEST(NonConstTest, StringPiece) {
912   std::string hello("hello");
913   MutableStringPiece sp(&hello.front(), hello.size());
914   sp[0] = 'x';
915   EXPECT_EQ("xello", hello);
916   {
917     StringPiece s(sp);
918     EXPECT_EQ("xello", s);
919   }
920   {
921     ByteRange r1(sp);
922     MutableByteRange r2(sp);
923   }
924 }