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