d2c8d064ec42dc453ed23fa794235ef1d6018e74
[WebKit-https.git] / Source / WTF / wtf / text / StringCommon.h
1 /*
2  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef StringCommon_h
27 #define StringCommon_h
28
29 #include <algorithm>
30 #include <unicode/uchar.h>
31 #include <wtf/ASCIICType.h>
32 #include <wtf/NotFound.h>
33
34 namespace WTF {
35
36 using CodeUnitMatchFunction = bool (*)(UChar);
37
38 template<typename CharacterTypeA, typename CharacterTypeB> bool equalIgnoringASCIICase(const CharacterTypeA*, const CharacterTypeB*, unsigned length);
39 template<typename CharacterTypeA, typename CharacterTypeB> bool equalIgnoringASCIICase(const CharacterTypeA*, unsigned lengthA, const CharacterTypeB*, unsigned lengthB);
40
41 template<typename StringClassA, typename StringClassB> bool equalIgnoringASCIICaseCommon(const StringClassA&, const StringClassB&);
42
43 template<typename CharacterType> bool equalLettersIgnoringASCIICase(const CharacterType*, const char* lowercaseLetters, unsigned length);
44 template<typename CharacterType, unsigned lowercaseLettersLength> bool equalLettersIgnoringASCIICase(const CharacterType*, unsigned charactersLength, const char (&lowercaseLetters)[lowercaseLettersLength]);
45
46 template<typename StringClass, unsigned length> bool equalLettersIgnoringASCIICaseCommon(const StringClass&, const char (&lowercaseLetters)[length]);
47
48 template<typename T>
49 inline T loadUnaligned(const char* s)
50 {
51 #if COMPILER(CLANG)
52     T tmp;
53     memcpy(&tmp, s, sizeof(T));
54     return tmp;
55 #else
56     // This may result in undefined behavior due to unaligned access.
57     return *reinterpret_cast<const T*>(s);
58 #endif
59 }
60
61 // Do comparisons 8 or 4 bytes-at-a-time on architectures where it's safe.
62 #if (CPU(X86_64) || CPU(ARM64)) && !ASAN_ENABLED
63 ALWAYS_INLINE bool equal(const LChar* aLChar, const LChar* bLChar, unsigned length)
64 {
65     unsigned dwordLength = length >> 3;
66
67     const char* a = reinterpret_cast<const char*>(aLChar);
68     const char* b = reinterpret_cast<const char*>(bLChar);
69
70     if (dwordLength) {
71         for (unsigned i = 0; i != dwordLength; ++i) {
72             if (loadUnaligned<uint64_t>(a) != loadUnaligned<uint64_t>(b))
73                 return false;
74
75             a += sizeof(uint64_t);
76             b += sizeof(uint64_t);
77         }
78     }
79
80     if (length & 4) {
81         if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))
82             return false;
83
84         a += sizeof(uint32_t);
85         b += sizeof(uint32_t);
86     }
87
88     if (length & 2) {
89         if (loadUnaligned<uint16_t>(a) != loadUnaligned<uint16_t>(b))
90             return false;
91
92         a += sizeof(uint16_t);
93         b += sizeof(uint16_t);
94     }
95
96     if (length & 1 && (*reinterpret_cast<const LChar*>(a) != *reinterpret_cast<const LChar*>(b)))
97         return false;
98
99     return true;
100 }
101
102 ALWAYS_INLINE bool equal(const UChar* aUChar, const UChar* bUChar, unsigned length)
103 {
104     unsigned dwordLength = length >> 2;
105
106     const char* a = reinterpret_cast<const char*>(aUChar);
107     const char* b = reinterpret_cast<const char*>(bUChar);
108
109     if (dwordLength) {
110         for (unsigned i = 0; i != dwordLength; ++i) {
111             if (loadUnaligned<uint64_t>(a) != loadUnaligned<uint64_t>(b))
112                 return false;
113
114             a += sizeof(uint64_t);
115             b += sizeof(uint64_t);
116         }
117     }
118
119     if (length & 2) {
120         if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))
121             return false;
122
123         a += sizeof(uint32_t);
124         b += sizeof(uint32_t);
125     }
126
127     if (length & 1 && (*reinterpret_cast<const UChar*>(a) != *reinterpret_cast<const UChar*>(b)))
128         return false;
129
130     return true;
131 }
132 #elif CPU(X86) && !ASAN_ENABLED
133 ALWAYS_INLINE bool equal(const LChar* aLChar, const LChar* bLChar, unsigned length)
134 {
135     const char* a = reinterpret_cast<const char*>(aLChar);
136     const char* b = reinterpret_cast<const char*>(bLChar);
137
138     unsigned wordLength = length >> 2;
139     for (unsigned i = 0; i != wordLength; ++i) {
140         if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))
141             return false;
142         a += sizeof(uint32_t);
143         b += sizeof(uint32_t);
144     }
145
146     length &= 3;
147
148     if (length) {
149         const LChar* aRemainder = reinterpret_cast<const LChar*>(a);
150         const LChar* bRemainder = reinterpret_cast<const LChar*>(b);
151
152         for (unsigned i = 0; i <  length; ++i) {
153             if (aRemainder[i] != bRemainder[i])
154                 return false;
155         }
156     }
157
158     return true;
159 }
160
161 ALWAYS_INLINE bool equal(const UChar* aUChar, const UChar* bUChar, unsigned length)
162 {
163     const char* a = reinterpret_cast<const char*>(aUChar);
164     const char* b = reinterpret_cast<const char*>(bUChar);
165
166     unsigned wordLength = length >> 1;
167     for (unsigned i = 0; i != wordLength; ++i) {
168         if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))
169             return false;
170         a += sizeof(uint32_t);
171         b += sizeof(uint32_t);
172     }
173
174     if (length & 1 && *reinterpret_cast<const UChar*>(a) != *reinterpret_cast<const UChar*>(b))
175         return false;
176
177     return true;
178 }
179 #elif PLATFORM(IOS) && WTF_ARM_ARCH_AT_LEAST(7) && !ASAN_ENABLED
180 ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)
181 {
182     bool isEqual = false;
183     uint32_t aValue;
184     uint32_t bValue;
185     asm("subs   %[length], #4\n"
186         "blo    2f\n"
187
188         "0:\n" // Label 0 = Start of loop over 32 bits.
189         "ldr    %[aValue], [%[a]], #4\n"
190         "ldr    %[bValue], [%[b]], #4\n"
191         "cmp    %[aValue], %[bValue]\n"
192         "bne    66f\n"
193         "subs   %[length], #4\n"
194         "bhs    0b\n"
195
196         // At this point, length can be:
197         // -0: 00000000000000000000000000000000 (0 bytes left)
198         // -1: 11111111111111111111111111111111 (3 bytes left)
199         // -2: 11111111111111111111111111111110 (2 bytes left)
200         // -3: 11111111111111111111111111111101 (1 byte left)
201         // -4: 11111111111111111111111111111100 (length was 0)
202         // The pointers are at the correct position.
203         "2:\n" // Label 2 = End of loop over 32 bits, check for pair of characters.
204         "tst    %[length], #2\n"
205         "beq    1f\n"
206         "ldrh   %[aValue], [%[a]], #2\n"
207         "ldrh   %[bValue], [%[b]], #2\n"
208         "cmp    %[aValue], %[bValue]\n"
209         "bne    66f\n"
210
211         "1:\n" // Label 1 = Check for a single character left.
212         "tst    %[length], #1\n"
213         "beq    42f\n"
214         "ldrb   %[aValue], [%[a]]\n"
215         "ldrb   %[bValue], [%[b]]\n"
216         "cmp    %[aValue], %[bValue]\n"
217         "bne    66f\n"
218
219         "42:\n" // Label 42 = Success.
220         "mov    %[isEqual], #1\n"
221         "66:\n" // Label 66 = End without changing isEqual to 1.
222         : [length]"+r"(length), [isEqual]"+r"(isEqual), [a]"+r"(a), [b]"+r"(b), [aValue]"+r"(aValue), [bValue]"+r"(bValue)
223         :
224         :
225         );
226     return isEqual;
227 }
228
229 ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length)
230 {
231     bool isEqual = false;
232     uint32_t aValue;
233     uint32_t bValue;
234     asm("subs   %[length], #2\n"
235         "blo    1f\n"
236
237         "0:\n" // Label 0 = Start of loop over 32 bits.
238         "ldr    %[aValue], [%[a]], #4\n"
239         "ldr    %[bValue], [%[b]], #4\n"
240         "cmp    %[aValue], %[bValue]\n"
241         "bne    66f\n"
242         "subs   %[length], #2\n"
243         "bhs    0b\n"
244
245         // At this point, length can be:
246         // -0: 00000000000000000000000000000000 (0 bytes left)
247         // -1: 11111111111111111111111111111111 (1 character left, 2 bytes)
248         // -2: 11111111111111111111111111111110 (length was zero)
249         // The pointers are at the correct position.
250         "1:\n" // Label 1 = Check for a single character left.
251         "tst    %[length], #1\n"
252         "beq    42f\n"
253         "ldrh   %[aValue], [%[a]]\n"
254         "ldrh   %[bValue], [%[b]]\n"
255         "cmp    %[aValue], %[bValue]\n"
256         "bne    66f\n"
257
258         "42:\n" // Label 42 = Success.
259         "mov    %[isEqual], #1\n"
260         "66:\n" // Label 66 = End without changing isEqual to 1.
261         : [length]"+r"(length), [isEqual]"+r"(isEqual), [a]"+r"(a), [b]"+r"(b), [aValue]"+r"(aValue), [bValue]"+r"(bValue)
262         :
263         :
264         );
265     return isEqual;
266 }
267 #elif !ASAN_ENABLED
268 ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length) { return !memcmp(a, b, length); }
269 ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length) { return !memcmp(a, b, length * sizeof(UChar)); }
270 #else
271 ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)
272 {
273     for (unsigned i = 0; i < length; ++i) {
274         if (a[i] != b[i])
275             return false;
276     }
277     return true;
278 }
279 ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length)
280 {
281     for (unsigned i = 0; i < length; ++i) {
282         if (a[i] != b[i])
283             return false;
284     }
285     return true;
286 }
287 #endif
288
289 ALWAYS_INLINE bool equal(const LChar* a, const UChar* b, unsigned length)
290 {
291     for (unsigned i = 0; i < length; ++i) {
292         if (a[i] != b[i])
293             return false;
294     }
295     return true;
296 }
297
298 ALWAYS_INLINE bool equal(const UChar* a, const LChar* b, unsigned length) { return equal(b, a, length); }
299
300 template<typename StringClassA, typename StringClassB>
301 ALWAYS_INLINE bool equalCommon(const StringClassA& a, const StringClassB& b)
302 {
303     unsigned length = a.length();
304     if (length != b.length())
305         return false;
306
307     if (a.is8Bit()) {
308         if (b.is8Bit())
309             return equal(a.characters8(), b.characters8(), length);
310
311         return equal(a.characters8(), b.characters16(), length);
312     }
313
314     if (b.is8Bit())
315         return equal(a.characters16(), b.characters8(), length);
316
317     return equal(a.characters16(), b.characters16(), length);
318 }
319
320 template<typename StringClassA, typename StringClassB>
321 ALWAYS_INLINE bool equalCommon(const StringClassA* a, const StringClassB* b)
322 {
323     if (a == b)
324         return true;
325     if (!a || !b)
326         return false;
327     return equal(*a, *b);
328 }
329
330 template<typename StringClass, unsigned length> bool equal(const StringClass& a, const UChar (&codeUnits)[length])
331 {
332     if (a.length() != length)
333         return false;
334
335     if (a.is8Bit())
336         return equal(a.characters8(), codeUnits, length);
337
338     return equal(a.characters16(), codeUnits, length);
339 }
340
341 template<typename CharacterTypeA, typename CharacterTypeB>
342 inline bool equalIgnoringASCIICase(const CharacterTypeA* a, const CharacterTypeB* b, unsigned length)
343 {
344     for (unsigned i = 0; i < length; ++i) {
345         if (toASCIILower(a[i]) != toASCIILower(b[i]))
346             return false;
347     }
348     return true;
349 }
350
351 template<typename CharacterTypeA, typename CharacterTypeB> inline bool equalIgnoringASCIICase(const CharacterTypeA* a, unsigned lengthA, const CharacterTypeB* b, unsigned lengthB)
352 {
353     return lengthA == lengthB && equalIgnoringASCIICase(a, b, lengthA);
354 }
355
356 template<typename StringClassA, typename StringClassB>
357 bool equalIgnoringASCIICaseCommon(const StringClassA& a, const StringClassB& b)
358 {
359     unsigned length = a.length();
360     if (length != b.length())
361         return false;
362
363     if (a.is8Bit()) {
364         if (b.is8Bit())
365             return equalIgnoringASCIICase(a.characters8(), b.characters8(), length);
366
367         return equalIgnoringASCIICase(a.characters8(), b.characters16(), length);
368     }
369
370     if (b.is8Bit())
371         return equalIgnoringASCIICase(a.characters16(), b.characters8(), length);
372
373     return equalIgnoringASCIICase(a.characters16(), b.characters16(), length);
374 }
375
376 template<typename StringClassA> bool equalIgnoringASCIICaseCommon(const StringClassA& a, const char* b)
377 {
378     unsigned length = a.length();
379     if (length != strlen(b))
380         return false;
381
382     if (a.is8Bit())
383         return equalIgnoringASCIICase(a.characters8(), b, length);
384
385     return equalIgnoringASCIICase(a.characters16(), b, length);
386 }
387
388 template<typename StringClassA, typename StringClassB>
389 bool startsWith(const StringClassA& reference, const StringClassB& prefix)
390 {
391     unsigned prefixLength = prefix.length();
392     if (prefixLength > reference.length())
393         return false;
394
395     if (reference.is8Bit()) {
396         if (prefix.is8Bit())
397             return equal(reference.characters8(), prefix.characters8(), prefixLength);
398         return equal(reference.characters8(), prefix.characters16(), prefixLength);
399     }
400     if (prefix.is8Bit())
401         return equal(reference.characters16(), prefix.characters8(), prefixLength);
402     return equal(reference.characters16(), prefix.characters16(), prefixLength);
403 }
404
405 template<typename StringClassA, typename StringClassB>
406 bool startsWithIgnoringASCIICase(const StringClassA& reference, const StringClassB& prefix)
407 {
408     unsigned prefixLength = prefix.length();
409     if (prefixLength > reference.length())
410         return false;
411
412     if (reference.is8Bit()) {
413         if (prefix.is8Bit())
414             return equalIgnoringASCIICase(reference.characters8(), prefix.characters8(), prefixLength);
415         return equalIgnoringASCIICase(reference.characters8(), prefix.characters16(), prefixLength);
416     }
417     if (prefix.is8Bit())
418         return equalIgnoringASCIICase(reference.characters16(), prefix.characters8(), prefixLength);
419     return equalIgnoringASCIICase(reference.characters16(), prefix.characters16(), prefixLength);
420 }
421
422 template<typename StringClassA, typename StringClassB>
423 bool endsWith(const StringClassA& reference, const StringClassB& suffix)
424 {
425     unsigned suffixLength = suffix.length();
426     unsigned referenceLength = reference.length();
427     if (suffixLength > referenceLength)
428         return false;
429
430     unsigned startOffset = referenceLength - suffixLength;
431
432     if (reference.is8Bit()) {
433         if (suffix.is8Bit())
434             return equal(reference.characters8() + startOffset, suffix.characters8(), suffixLength);
435         return equal(reference.characters8() + startOffset, suffix.characters16(), suffixLength);
436     }
437     if (suffix.is8Bit())
438         return equal(reference.characters16() + startOffset, suffix.characters8(), suffixLength);
439     return equal(reference.characters16() + startOffset, suffix.characters16(), suffixLength);
440 }
441
442 template<typename StringClassA, typename StringClassB>
443 bool endsWithIgnoringASCIICase(const StringClassA& reference, const StringClassB& suffix)
444 {
445     unsigned suffixLength = suffix.length();
446     unsigned referenceLength = reference.length();
447     if (suffixLength > referenceLength)
448         return false;
449
450     unsigned startOffset = referenceLength - suffixLength;
451
452     if (reference.is8Bit()) {
453         if (suffix.is8Bit())
454             return equalIgnoringASCIICase(reference.characters8() + startOffset, suffix.characters8(), suffixLength);
455         return equalIgnoringASCIICase(reference.characters8() + startOffset, suffix.characters16(), suffixLength);
456     }
457     if (suffix.is8Bit())
458         return equalIgnoringASCIICase(reference.characters16() + startOffset, suffix.characters8(), suffixLength);
459     return equalIgnoringASCIICase(reference.characters16() + startOffset, suffix.characters16(), suffixLength);
460 }
461
462 template <typename SearchCharacterType, typename MatchCharacterType>
463 size_t findIgnoringASCIICase(const SearchCharacterType* source, const MatchCharacterType* matchCharacters, unsigned startOffset, unsigned searchLength, unsigned matchLength)
464 {
465     ASSERT(searchLength >= matchLength);
466
467     const SearchCharacterType* startSearchedCharacters = source + startOffset;
468
469     // delta is the number of additional times to test; delta == 0 means test only once.
470     unsigned delta = searchLength - matchLength;
471
472     for (unsigned i = 0; i <= delta; ++i) {
473         if (equalIgnoringASCIICase(startSearchedCharacters + i, matchCharacters, matchLength))
474             return startOffset + i;
475     }
476     return notFound;
477 }
478
479 template<typename StringClassA, typename StringClassB>
480 size_t findIgnoringASCIICase(const StringClassA& source, const StringClassB& stringToFind, unsigned startOffset)
481 {
482     unsigned sourceStringLength = source.length();
483     unsigned matchLength = stringToFind.length();
484     if (!matchLength)
485         return std::min(startOffset, sourceStringLength);
486
487     // Check startOffset & matchLength are in range.
488     if (startOffset > sourceStringLength)
489         return notFound;
490     unsigned searchLength = sourceStringLength - startOffset;
491     if (matchLength > searchLength)
492         return notFound;
493
494     if (source.is8Bit()) {
495         if (stringToFind.is8Bit())
496             return findIgnoringASCIICase(source.characters8(), stringToFind.characters8(), startOffset, searchLength, matchLength);
497         return findIgnoringASCIICase(source.characters8(), stringToFind.characters16(), startOffset, searchLength, matchLength);
498     }
499
500     if (stringToFind.is8Bit())
501         return findIgnoringASCIICase(source.characters16(), stringToFind.characters8(), startOffset, searchLength, matchLength);
502
503     return findIgnoringASCIICase(source.characters16(), stringToFind.characters16(), startOffset, searchLength, matchLength);
504 }
505
506 template <typename SearchCharacterType, typename MatchCharacterType>
507 ALWAYS_INLINE static size_t findInner(const SearchCharacterType* searchCharacters, const MatchCharacterType* matchCharacters, unsigned index, unsigned searchLength, unsigned matchLength)
508 {
509     // Optimization: keep a running hash of the strings,
510     // only call equal() if the hashes match.
511
512     // delta is the number of additional times to test; delta == 0 means test only once.
513     unsigned delta = searchLength - matchLength;
514
515     unsigned searchHash = 0;
516     unsigned matchHash = 0;
517
518     for (unsigned i = 0; i < matchLength; ++i) {
519         searchHash += searchCharacters[i];
520         matchHash += matchCharacters[i];
521     }
522
523     unsigned i = 0;
524     // keep looping until we match
525     while (searchHash != matchHash || !equal(searchCharacters + i, matchCharacters, matchLength)) {
526         if (i == delta)
527             return notFound;
528         searchHash += searchCharacters[i + matchLength];
529         searchHash -= searchCharacters[i];
530         ++i;
531     }
532     return index + i;
533 }
534
535 template<typename CharacterType>
536 inline size_t find(const CharacterType* characters, unsigned length, CharacterType matchCharacter, unsigned index = 0)
537 {
538     while (index < length) {
539         if (characters[index] == matchCharacter)
540             return index;
541         ++index;
542     }
543     return notFound;
544 }
545
546 ALWAYS_INLINE size_t find(const UChar* characters, unsigned length, LChar matchCharacter, unsigned index = 0)
547 {
548     return find(characters, length, static_cast<UChar>(matchCharacter), index);
549 }
550
551 inline size_t find(const LChar* characters, unsigned length, UChar matchCharacter, unsigned index = 0)
552 {
553     if (matchCharacter & ~0xFF)
554         return notFound;
555     return find(characters, length, static_cast<LChar>(matchCharacter), index);
556 }
557
558 template<typename StringClass>
559 size_t findCommon(const StringClass& haystack, const StringClass& needle, unsigned start)
560 {
561     unsigned needleLength = needle.length();
562
563     if (needleLength == 1) {
564         if (haystack.is8Bit())
565             return WTF::find(haystack.characters8(), haystack.length(), needle[0], start);
566         return WTF::find(haystack.characters16(), haystack.length(), needle[0], start);
567     }
568
569     if (!needleLength)
570         return std::min(start, haystack.length());
571
572     if (start > haystack.length())
573         return notFound;
574     unsigned searchLength = haystack.length() - start;
575     if (needleLength > searchLength)
576         return notFound;
577
578     if (haystack.is8Bit()) {
579         if (needle.is8Bit())
580             return findInner(haystack.characters8() + start, needle.characters8(), start, searchLength, needleLength);
581         return findInner(haystack.characters8() + start, needle.characters16(), start, searchLength, needleLength);
582     }
583
584     if (needle.is8Bit())
585         return findInner(haystack.characters16() + start, needle.characters8(), start, searchLength, needleLength);
586
587     return findInner(haystack.characters16() + start, needle.characters16(), start, searchLength, needleLength);
588 }
589
590 // This is marked inline since it's mostly used in non-inline functions for each string type.
591 // When used directly in code it's probably OK to be inline; maybe the loop will be unrolled.
592 template<typename CharacterType> inline bool equalLettersIgnoringASCIICase(const CharacterType* characters, const char* lowercaseLetters, unsigned length)
593 {
594     for (unsigned i = 0; i < length; ++i) {
595         if (!isASCIIAlphaCaselessEqual(characters[i], lowercaseLetters[i]))
596             return false;
597     }
598     return true;
599 }
600
601 template<typename CharacterType, unsigned lowercaseLettersLength> inline bool equalLettersIgnoringASCIICase(const CharacterType* characters, unsigned charactersLength, const char (&lowercaseLetters)[lowercaseLettersLength])
602 {
603     ASSERT(strlen(lowercaseLetters) == lowercaseLettersLength - 1);
604     unsigned lowercaseLettersStringLength = lowercaseLettersLength - 1;
605     return charactersLength == lowercaseLettersStringLength && equalLettersIgnoringASCIICase(characters, lowercaseLetters, lowercaseLettersStringLength);
606 }
607
608 template<typename StringClass> bool inline hasPrefixWithLettersIgnoringASCIICaseCommon(const StringClass& string, const char* lowercaseLetters, unsigned length)
609 {
610 #if !ASSERT_DISABLED
611     ASSERT(*lowercaseLetters);
612     for (const char* letter = lowercaseLetters; *letter; ++letter)
613         ASSERT(toASCIILowerUnchecked(*letter) == *letter);
614 #endif
615     ASSERT(string.length() >= length);
616
617     if (string.is8Bit())
618         return equalLettersIgnoringASCIICase(string.characters8(), lowercaseLetters, length);
619     return equalLettersIgnoringASCIICase(string.characters16(), lowercaseLetters, length);
620 }
621
622 // This is intentionally not marked inline because it's used often and is not speed-critical enough to want it inlined everywhere.
623 template<typename StringClass> bool equalLettersIgnoringASCIICaseCommonWithoutLength(const StringClass& string, const char* lowercaseLetters)
624 {
625     unsigned length = string.length();
626     if (length != strlen(lowercaseLetters))
627         return false;
628     return hasPrefixWithLettersIgnoringASCIICaseCommon(string, lowercaseLetters, length);
629 }
630
631 template<typename StringClass> bool startsWithLettersIgnoringASCIICaseCommonWithoutLength(const StringClass& string, const char* lowercaseLetters)
632 {
633     size_t prefixLength = strlen(lowercaseLetters);
634     if (!prefixLength)
635         return true;
636     if (string.length() < prefixLength)
637         return false;
638     return hasPrefixWithLettersIgnoringASCIICaseCommon(string, lowercaseLetters, prefixLength);
639 }
640
641 template<typename StringClass, unsigned length> inline bool equalLettersIgnoringASCIICaseCommon(const StringClass& string, const char (&lowercaseLetters)[length])
642 {
643     // Don't actually use the length; we are choosing code size over speed.
644     ASSERT(strlen(lowercaseLetters) == length - 1);
645     const char* pointer = lowercaseLetters;
646     return equalLettersIgnoringASCIICaseCommonWithoutLength(string, pointer);
647 }
648
649 template<typename StringClass, unsigned length> inline bool startsWithLettersIgnoringASCIICaseCommon(const StringClass& string, const char (&lowercaseLetters)[length])
650 {
651     const char* pointer = lowercaseLetters;
652     return startsWithLettersIgnoringASCIICaseCommonWithoutLength(string, pointer);
653 }
654
655 }
656
657 using WTF::equalIgnoringASCIICase;
658 using WTF::equalLettersIgnoringASCIICase;
659
660 #endif