GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/string_search.h Lines: 233 242 96.3 %
Date: 2019-01-07 12:15:22 Branches: 162 272 59.6 %

Line Branch Exec Source
1
// Copyright 2011 the V8 project authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
#ifndef SRC_STRING_SEARCH_H_
6
#define SRC_STRING_SEARCH_H_
7
8
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
9
10
#include "node_internals.h"
11
#include <string.h>
12
#include <algorithm>
13
14
namespace node {
15
namespace stringsearch {
16
17
template <typename T>
18
class Vector {
19
 public:
20
26870
  Vector(T* data, size_t length, bool isForward)
21
26870
      : start_(data), length_(length), is_forward_(isForward) {
22



26870
    CHECK(length > 0 && data != nullptr);
23
26870
  }
24
25
  // Returns the start of the memory range.
26
  // For vector v this is NOT necessarily &v[0], see forward().
27
4657005
  const T* start() const { return start_; }
28
29
  // Returns the length of the vector, in characters.
30
11753207
  size_t length() const { return length_; }
31
32
  // Returns true if the Vector is front-to-back, false if back-to-front.
33
  // In the latter case, v[0] corresponds to the *end* of the memory range.
34
4657005
  size_t forward() const { return is_forward_; }
35
36
  // Access individual vector elements - checks bounds in debug mode.
37
48029440
  T& operator[](size_t index) const {
38
    DCHECK_LT(index, length_);
39

48029440
    return start_[is_forward_ ? index : (length_ - index - 1)];
40
  }
41
42
 private:
43
  T* start_;
44
  size_t length_;
45
  bool is_forward_;
46
};
47
48
49
//---------------------------------------------------------------------
50
// String Search object.
51
//---------------------------------------------------------------------
52
53
// Class holding constants and methods that apply to all string search variants,
54
// independently of subject and pattern char size.
55
13435
class StringSearchBase {
56
 protected:
57
  // Cap on the maximal shift in the Boyer-Moore implementation. By setting a
58
  // limit, we can fix the size of tables. For a needle longer than this limit,
59
  // search will not be optimal, since we only build tables for a suffix
60
  // of the string, but it is a safe approximation.
61
  static const int kBMMaxShift = 250;
62
63
  // Reduce alphabet to this size.
64
  // One of the tables used by Boyer-Moore and Boyer-Moore-Horspool has size
65
  // proportional to the input alphabet. We reduce the alphabet size by
66
  // equating input characters modulo a smaller alphabet size. This gives
67
  // a potentially less efficient searching, but is a safe approximation.
68
  // For needles using only characters in the same Unicode 256-code point page,
69
  // there is no search speed degradation.
70
  static const int kLatin1AlphabetSize = 256;
71
  static const int kUC16AlphabetSize = 256;
72
73
  // Bad-char shift table stored in the state. It's length is the alphabet size.
74
  // For patterns below this length, the skip length of Boyer-Moore is too short
75
  // to compensate for the algorithmic overhead compared to simple brute force.
76
  static const int kBMMinPatternLength = 8;
77
78
  // Store for the BoyerMoore(Horspool) bad char shift table.
79
  int bad_char_shift_table_[kUC16AlphabetSize];
80
  // Store for the BoyerMoore good suffix shift table.
81
  int good_suffix_shift_table_[kBMMaxShift + 1];
82
  // Table used temporarily while building the BoyerMoore good suffix
83
  // shift table.
84
  int suffix_table_[kBMMaxShift + 1];
85
};
86
87
template <typename Char>
88
class StringSearch : private StringSearchBase {
89
 public:
90
  typedef stringsearch::Vector<const Char> Vector;
91
92
13435
  explicit StringSearch(Vector pattern)
93
13435
      : pattern_(pattern), start_(0) {
94

13435
    if (pattern.length() >= kBMMaxShift) {
95
11
      start_ = pattern.length() - kBMMaxShift;
96
    }
97
98
13435
    size_t pattern_length = pattern_.length();
99

13435
    CHECK_GT(pattern_length, 0);
100

13435
    if (pattern_length < kBMMinPatternLength) {
101

12760
      if (pattern_length == 1) {
102
191
        strategy_ = &StringSearch::SingleCharSearch;
103
12951
        return;
104
      }
105
12569
      strategy_ = &StringSearch::LinearSearch;
106
12569
      return;
107
    }
108
675
    strategy_ = &StringSearch::InitialSearch;
109
  }
110
111
13435
  size_t Search(Vector subject, size_t index) {
112

13435
    return (this->*strategy_)(subject, index);
113
  }
114
115
27
  static inline int AlphabetSize() {
116
    if (sizeof(Char) == 1) {
117
      // Latin1 needle.
118
27
      return kLatin1AlphabetSize;
119
    } else {
120
      // UC16 needle.
121
      return kUC16AlphabetSize;
122
    }
123
124
    static_assert(sizeof(Char) == sizeof(uint8_t) ||
125
                  sizeof(Char) == sizeof(uint16_t),
126
                  "sizeof(Char) == sizeof(uint16_t) || sizeof(uint8_t)");
127
  }
128
129
 private:
130
  typedef size_t (StringSearch::*SearchFunction)(Vector, size_t);
131
  size_t SingleCharSearch(Vector subject, size_t start_index);
132
  size_t LinearSearch(Vector subject, size_t start_index);
133
  size_t InitialSearch(Vector subject, size_t start_index);
134
  size_t BoyerMooreHorspoolSearch(Vector subject, size_t start_index);
135
  size_t BoyerMooreSearch(Vector subject, size_t start_index);
136
137
  void PopulateBoyerMooreHorspoolTable();
138
139
  void PopulateBoyerMooreTable();
140
141
63983
  static inline int CharOccurrence(int* bad_char_occurrence,
142
                                   Char char_code) {
143
    if (sizeof(Char) == 1) {
144
63983
      return bad_char_occurrence[static_cast<int>(char_code)];
145
    }
146
    // Both pattern and subject are UC16. Reduce character to equivalence class.
147
    int equiv_class = char_code % kUC16AlphabetSize;
148
    return bad_char_occurrence[equiv_class];
149
  }
150
151
  // The pattern to search for.
152
  Vector pattern_;
153
  // Pointer to implementation of the search.
154
  SearchFunction strategy_;
155
  // Cache value of Max(0, pattern_length() - kBMMaxShift)
156
  size_t start_;
157
};
158
159
160
template <typename T, typename U>
161
6960
inline T AlignDown(T value, U alignment) {
162
  return reinterpret_cast<T>(
163
6960
      (reinterpret_cast<uintptr_t>(value) & ~(alignment - 1)));
164
}
165
166
167
143
inline uint8_t GetHighestValueByte(uint16_t character) {
168
  return std::max(static_cast<uint8_t>(character & 0xFF),
169
143
                  static_cast<uint8_t>(character >> 8));
170
}
171
172
173
inline uint8_t GetHighestValueByte(uint8_t character) { return character; }
174
175
176
// Searches for a byte value in a memory buffer, back to front.
177
// Uses memrchr(3) on systems which support it, for speed.
178
// Falls back to a vanilla for loop on non-GNU systems such as Windows.
179
366239
inline const void* MemrchrFill(const void* haystack, uint8_t needle,
180
                               size_t haystack_len) {
181
#ifdef _GNU_SOURCE
182
366239
  return memrchr(haystack, needle, haystack_len);
183
#else
184
  const uint8_t* haystack8 = static_cast<const uint8_t*>(haystack);
185
  for (size_t i = haystack_len - 1; i != static_cast<size_t>(-1); i--) {
186
    if (haystack8[i] == needle) {
187
      return haystack8 + i;
188
    }
189
  }
190
  return nullptr;
191
#endif
192
}
193
194
195
// Finds the first occurrence of *two-byte* character pattern[0] in the string
196
// `subject`. Does not check that the whole pattern matches.
197
template <typename Char>
198
143
inline size_t FindFirstCharacter(Vector<const Char> pattern,
199
                                 Vector<const Char> subject, size_t index) {
200
143
  const Char pattern_first_char = pattern[0];
201
143
  const size_t max_n = (subject.length() - pattern.length() + 1);
202
203
  // For speed, search for the more `rare` of the two bytes in pattern[0]
204
  // using memchr / memrchr (which are much faster than a simple for loop).
205
143
  const uint8_t search_byte = GetHighestValueByte(pattern_first_char);
206
143
  size_t pos = index;
207
6828
  do {
208
6971
    const size_t bytes_to_search = (max_n - pos) * sizeof(Char);
209
    const void* void_pos;
210
6971
    if (subject.forward()) {
211
      // Assert that bytes_to_search won't overflow
212
6970
      CHECK_LE(pos, max_n);
213
6970
      CHECK_LE(max_n - pos, SIZE_MAX / sizeof(Char));
214
6970
      void_pos = memchr(subject.start() + pos, search_byte, bytes_to_search);
215
    } else {
216
1
      CHECK_LE(pos, subject.length());
217
1
      CHECK_LE(subject.length() - pos, SIZE_MAX / sizeof(Char));
218
1
      void_pos = MemrchrFill(subject.start() + pattern.length() - 1,
219
                             search_byte,
220
1
                             bytes_to_search);
221
    }
222
6971
    const Char* char_pos = static_cast<const Char*>(void_pos);
223
6971
    if (char_pos == nullptr)
224
11
      return subject.length();
225
226
    // Then, for each match, verify that the full two bytes match pattern[0].
227
6960
    char_pos = AlignDown(char_pos, sizeof(Char));
228
6960
    size_t raw_pos = static_cast<size_t>(char_pos - subject.start());
229
6960
    pos = subject.forward() ? raw_pos : (subject.length() - raw_pos - 1);
230
6960
    if (subject[pos] == pattern_first_char) {
231
      // Match found, hooray.
232
132
      return pos;
233
    }
234
    // Search byte matched, but the other byte of pattern[0] didn't. Keep going.
235
  } while (++pos < max_n);
236
237
  return subject.length();
238
}
239
240
241
// Finds the first occurrence of the byte pattern[0] in string `subject`.
242
// Does not verify that the whole pattern matches.
243
template <>
244
2324808
inline size_t FindFirstCharacter(Vector<const uint8_t> pattern,
245
                                 Vector<const uint8_t> subject,
246
                                 size_t index) {
247
2324808
  const uint8_t pattern_first_char = pattern[0];
248
2324808
  const size_t subj_len = subject.length();
249
2324808
  const size_t max_n = (subject.length() - pattern.length() + 1);
250
251
  const void* pos;
252
2324808
  if (subject.forward()) {
253
1958578
    pos = memchr(subject.start() + index, pattern_first_char, max_n - index);
254
  } else {
255
366230
    pos = MemrchrFill(subject.start() + pattern.length() - 1,
256
                      pattern_first_char,
257
732460
                      max_n - index);
258
  }
259
2324808
  const uint8_t* char_pos = static_cast<const uint8_t*>(pos);
260
2324808
  if (char_pos == nullptr) {
261
6542
    return subj_len;
262
  }
263
264
2318266
  size_t raw_pos = static_cast<size_t>(char_pos - subject.start());
265
2318266
  return subject.forward() ? raw_pos : (subj_len - raw_pos - 1);
266
}
267
268
//---------------------------------------------------------------------
269
// Single Character Pattern Search Strategy
270
//---------------------------------------------------------------------
271
272
template <typename Char>
273
191
size_t StringSearch<Char>::SingleCharSearch(
274
    Vector subject,
275
    size_t index) {
276

191
  CHECK_EQ(1, pattern_.length());
277
191
  return FindFirstCharacter(pattern_, subject, index);
278
}
279
280
//---------------------------------------------------------------------
281
// Linear Search Strategy
282
//---------------------------------------------------------------------
283
284
// Simple linear search for short patterns. Never bails out.
285
template <typename Char>
286
12569
size_t StringSearch<Char>::LinearSearch(
287
    Vector subject,
288
    size_t index) {
289

12569
  CHECK_GT(pattern_.length(), 1);
290
12569
  const size_t n = subject.length() - pattern_.length();
291

1951056
  for (size_t i = index; i <= n; i++) {
292
1951053
    i = FindFirstCharacter(pattern_, subject, i);
293

1951053
    if (i == subject.length())
294
19081
      return subject.length();
295

1944538
    CHECK_LE(i, n);
296
297
1944538
    bool matches = true;
298

2014753
    for (size_t j = 1; j < pattern_.length(); j++) {
299

2008702
      if (pattern_[j] != subject[i + j]) {
300
1938487
        matches = false;
301
1938487
        break;
302
      }
303
    }
304

1944538
    if (matches) {
305
6051
      return i;
306
    }
307
  }
308
3
  return subject.length();
309
}
310
311
//---------------------------------------------------------------------
312
// Boyer-Moore string search
313
//---------------------------------------------------------------------
314
315
template <typename Char>
316
3
size_t StringSearch<Char>::BoyerMooreSearch(
317
    Vector subject,
318
    size_t start_index) {
319
3
  const size_t subject_length = subject.length();
320
3
  const size_t pattern_length = pattern_.length();
321
  // Only preprocess at most kBMMaxShift last characters of pattern.
322
3
  size_t start = start_;
323
324
3
  int* bad_char_occurrence = bad_char_shift_table_;
325
3
  int* good_suffix_shift = good_suffix_shift_table_ - start_;
326
327
3
  Char last_char = pattern_[pattern_length - 1];
328
3
  size_t index = start_index;
329
  // Continue search from i.
330

14366
  while (index <= subject_length - pattern_length) {
331
14363
    size_t j = pattern_length - 1;
332
    int c;
333

31794
    while (last_char != (c = subject[index + j])) {
334
3068
      int shift = j - CharOccurrence(bad_char_occurrence, c);
335
3068
      index += shift;
336

3068
      if (index > subject_length - pattern_length) {
337
        return subject.length();
338
      }
339
    }
340

7549468
    while (pattern_[j] == (c = subject[index + j])) {
341

7520745
      if (j == 0) {
342
3
        return index;
343
      }
344
7520742
      j--;
345
    }
346

14360
    if (j < start) {
347
      // we have matched more than our tables allow us to be smart about.
348
      // Fall back on BMH shift.
349
2324
      index += pattern_length - 1 -
350
               CharOccurrence(bad_char_occurrence,
351
2324
                              static_cast<Char>(last_char));
352
    } else {
353
12036
      int gs_shift = good_suffix_shift[j + 1];
354
12036
      int bc_occ = CharOccurrence(bad_char_occurrence, c);
355
12036
      int shift = j - bc_occ;
356

12036
      if (gs_shift > shift) {
357
12036
        shift = gs_shift;
358
      }
359
12036
      index += shift;
360
    }
361
  }
362
363
  return subject.length();
364
}
365
366
template <typename Char>
367
3
void StringSearch<Char>::PopulateBoyerMooreTable() {
368
3
  const size_t pattern_length = pattern_.length();
369
  // Only look at the last kBMMaxShift characters of pattern (from start_
370
  // to pattern_length).
371
3
  const size_t start = start_;
372
3
  const size_t length = pattern_length - start;
373
374
  // Biased tables so that we can use pattern indices as table indices,
375
  // even if we only cover the part of the pattern from offset start.
376
3
  int* shift_table = good_suffix_shift_table_ - start_;
377
3
  int* suffix_table = suffix_table_ - start_;
378
379
  // Initialize table.
380

753
  for (size_t i = start; i < pattern_length; i++) {
381
750
    shift_table[i] = length;
382
  }
383
3
  shift_table[pattern_length] = 1;
384
3
  suffix_table[pattern_length] = pattern_length + 1;
385
386

3
  if (pattern_length <= start) {
387
3
    return;
388
  }
389
390
  // Find suffixes.
391
3
  Char last_char = pattern_[pattern_length - 1];
392
3
  size_t suffix = pattern_length + 1;
393
  {
394
3
    size_t i = pattern_length;
395

711
    while (i > start) {
396
705
      Char c = pattern_[i - 1];
397



1449
      while (suffix <= pattern_length && c != pattern_[suffix - 1]) {
398

39
        if (static_cast<size_t>(shift_table[suffix]) == length) {
399
14
          shift_table[suffix] = suffix - i;
400
        }
401
39
        suffix = suffix_table[suffix];
402
      }
403
705
      suffix_table[--i] = --suffix;
404

705
      if (suffix == pattern_length) {
405
        // No suffix to extend, so we check against last_char only.
406



48
        while ((i > start) && (pattern_[i - 1] != last_char)) {
407

42
          if (static_cast<size_t>(shift_table[pattern_length]) == length) {
408
            shift_table[pattern_length] = pattern_length - i;
409
          }
410
42
          suffix_table[--i] = pattern_length;
411
        }
412

3
        if (i > start) {
413
3
          suffix_table[--i] = --suffix;
414
        }
415
      }
416
    }
417
  }
418
  // Build shift table using suffixes.
419

3
  if (suffix < pattern_length) {
420

756
    for (size_t i = start; i <= pattern_length; i++) {
421

753
      if (static_cast<size_t>(shift_table[i]) == length) {
422
736
        shift_table[i] = suffix - start;
423
      }
424

753
      if (i == suffix) {
425
8
        suffix = suffix_table[suffix];
426
      }
427
    }
428
  }
429
}
430
431
//---------------------------------------------------------------------
432
// Boyer-Moore-Horspool string search.
433
//---------------------------------------------------------------------
434
435
template <typename Char>
436
27
size_t StringSearch<Char>::BoyerMooreHorspoolSearch(
437
    Vector subject,
438
    size_t start_index) {
439
27
  const size_t subject_length = subject.length();
440
27
  const size_t pattern_length = pattern_.length();
441
27
  int* char_occurrences = bad_char_shift_table_;
442
27
  int64_t badness = -pattern_length;
443
444
  // How bad we are doing without a good-suffix table.
445
27
  Char last_char = pattern_[pattern_length - 1];
446
  int last_char_shift =
447
      pattern_length - 1 -
448
27
      CharOccurrence(char_occurrences, static_cast<Char>(last_char));
449
450
  // Perform search
451
27
  size_t index = start_index;  // No matches found prior to this index.
452

31504
  while (index <= subject_length - pattern_length) {
453
31477
    size_t j = pattern_length - 1;
454
    int subject_char;
455

109480
    while (last_char != (subject_char = subject[index + j])) {
456
46528
      int bc_occ = CharOccurrence(char_occurrences, subject_char);
457
46528
      int shift = j - bc_occ;
458
46528
      index += shift;
459
46528
      badness += 1 - shift;  // at most zero, so badness cannot increase.
460

46528
      if (index > subject_length - pattern_length) {
461
2
        return subject_length;
462
      }
463
    }
464
31475
    j--;
465

2754114
    while (pattern_[j] == (subject[index + j])) {
466

2691186
      if (j == 0) {
467
22
        return index;
468
      }
469
2691164
      j--;
470
    }
471
31453
    index += last_char_shift;
472
    // Badness increases by the number of characters we have
473
    // checked, and decreases by the number of characters we
474
    // can skip by shifting. It's a measure of how we are doing
475
    // compared to reading each character exactly once.
476
31453
    badness += (pattern_length - j) - last_char_shift;
477

31453
    if (badness > 0) {
478
3
      PopulateBoyerMooreTable();
479
3
      strategy_ = &StringSearch::BoyerMooreSearch;
480
3
      return BoyerMooreSearch(subject, index);
481
    }
482
  }
483
  return subject.length();
484
}
485
486
template <typename Char>
487
27
void StringSearch<Char>::PopulateBoyerMooreHorspoolTable() {
488
27
  const size_t pattern_length = pattern_.length();
489
490
27
  int* bad_char_occurrence = bad_char_shift_table_;
491
492
  // Only preprocess at most kBMMaxShift last characters of pattern.
493
27
  const size_t start = start_;
494
  // Run forwards to populate bad_char_table, so that *last* instance
495
  // of character equivalence class is the one registered.
496
  // Notice: Doesn't include the last character.
497
27
  const size_t table_size = AlphabetSize();
498

27
  if (start == 0) {
499
    // All patterns less than kBMMaxShift in length.
500
20
    memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence));
501
  } else {
502

1799
    for (size_t i = 0; i < table_size; i++) {
503
1792
      bad_char_occurrence[i] = start - 1;
504
    }
505
  }
506

2614
  for (size_t i = start; i < pattern_length - 1; i++) {
507
2587
    Char c = pattern_[i];
508
2587
    int bucket = (sizeof(Char) == 1) ? c : c % AlphabetSize();
509
2587
    bad_char_occurrence[bucket] = i;
510
  }
511
27
}
512
513
//---------------------------------------------------------------------
514
// Linear string search with bailout to BMH.
515
//---------------------------------------------------------------------
516
517
// Simple linear search for short patterns, which bails out if the string
518
// isn't found very early in the subject. Upgrades to BoyerMooreHorspool.
519
template <typename Char>
520
675
size_t StringSearch<Char>::InitialSearch(
521
    Vector subject,
522
    size_t index) {
523
675
  const size_t pattern_length = pattern_.length();
524
  // Badness is a count of how much work we have done.  When we have
525
  // done enough work we decide it's probably worth switching to a better
526
  // algorithm.
527
675
  int64_t badness = -10 - (pattern_length << 2);
528
529
  // We know our pattern is at least 2 characters, we cache the first so
530
  // the common case of the first character not matching is faster.
531

373734
  for (size_t i = index, n = subject.length() - pattern_length; i <= n; i++) {
532
373734
    badness++;
533

373734
    if (badness <= 0) {
534
373707
      i = FindFirstCharacter(pattern_, subject, i);
535

373707
      if (i == subject.length())
536
678
        return subject.length();
537

373704
      CHECK_LE(i, n);
538
373704
      size_t j = 1;
539

10159487
      do {
540

10532546
        if (pattern_[j] != subject[i + j]) {
541
373059
          break;
542
        }
543
10159487
        j++;
544
      } while (j < pattern_length);
545

373704
      if (j == pattern_length) {
546
645
        return i;
547
      }
548
373059
      badness += j;
549
    } else {
550
27
      PopulateBoyerMooreHorspoolTable();
551
27
      strategy_ = &StringSearch::BoyerMooreHorspoolSearch;
552
27
      return BoyerMooreHorspoolSearch(subject, i);
553
    }
554
  }
555
  return subject.length();
556
}
557
558
// Perform a single stand-alone search.
559
// If searching multiple times for the same pattern, a search
560
// object should be constructed once and the Search function then called
561
// for each search.
562
template <typename Char>
563
13435
size_t SearchString(Vector<const Char> subject,
564
                    Vector<const Char> pattern,
565
                    size_t start_index) {
566
13435
  StringSearch<Char> search(pattern);
567
13435
  return search.Search(subject, start_index);
568
}
569
}  // namespace stringsearch
570
}  // namespace node
571
572
namespace node {
573
574
template <typename Char>
575
13436
size_t SearchString(const Char* haystack,
576
                    size_t haystack_length,
577
                    const Char* needle,
578
                    size_t needle_length,
579
                    size_t start_index,
580
                    bool is_forward) {
581

13436
  if (haystack_length < needle_length) return haystack_length;
582
  // To do a reverse search (lastIndexOf instead of indexOf) without redundant
583
  // code, create two vectors that are reversed views into the input strings.
584
  // For example, v_needle[0] would return the *last* character of the needle.
585
  // So we're searching for the first instance of rev(needle) in rev(haystack)
586
13435
  stringsearch::Vector<const Char> v_needle(needle, needle_length, is_forward);
587
  stringsearch::Vector<const Char> v_haystack(
588
13435
      haystack, haystack_length, is_forward);
589
13435
  size_t diff = haystack_length - needle_length;
590
  size_t relative_start_index;
591

13435
  if (is_forward) {
592
13360
    relative_start_index = start_index;
593

75
  } else if (diff < start_index) {
594
31
    relative_start_index = 0;
595
  } else {
596
44
    relative_start_index = diff - start_index;
597
  }
598
  size_t pos = node::stringsearch::SearchString(
599
13435
      v_haystack, v_needle, relative_start_index);
600

13435
  if (pos == haystack_length) {
601
    // not found
602
6558
    return pos;
603
  }
604

6877
  return is_forward ? pos : (haystack_length - needle_length - pos);
605
}
606
607
template <size_t N>
608
12395
size_t SearchString(const char* haystack, size_t haystack_length,
609
                    const char (&needle)[N]) {
610
  return SearchString(
611
      reinterpret_cast<const uint8_t*>(haystack), haystack_length,
612
12395
      reinterpret_cast<const uint8_t*>(needle), N - 1, 0, true);
613
}
614
615
}  // namespace node
616
617
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
618
619
#endif  // SRC_STRING_SEARCH_H_