1 // Copyright 2020 The Chromium Authors
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 BASE_STRINGS_STRING_UTIL_INTERNAL_H_
6 #define BASE_STRINGS_STRING_UTIL_INTERNAL_H_
7
8 #include <type_traits>
9
10 #include "base/ranges/algorithm.h"
11 #include "base/strings/string_piece.h"
12
13 namespace base::internal {
14
15 // ASCII-specific tolower. The standard library's tolower is locale sensitive,
16 // so we don't want to use it here.
17 template <typename CharT,
18 typename = std::enable_if_t<std::is_integral<CharT>::value>>
ToLowerASCII(CharT c)19 constexpr CharT ToLowerASCII(CharT c) {
20 return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
21 }
22
23 template <typename T>
CompareCaseInsensitiveASCIIT(T a,T b)24 constexpr int CompareCaseInsensitiveASCIIT(T a, T b) {
25 // Find the first characters that aren't equal and compare them. If the end
26 // of one of the strings is found before a nonequal character, the lengths
27 // of the strings are compared. Compare using the unsigned type so the sort
28 // order is independent of the signedness of `char`.
29 static_assert(std::is_integral_v<typename T::value_type>);
30 using UCharT = std::make_unsigned_t<typename T::value_type>;
31 size_t i = 0;
32 while (i < a.length() && i < b.length()) {
33 UCharT lower_a = static_cast<UCharT>(ToLowerASCII(a[i]));
34 UCharT lower_b = static_cast<UCharT>(ToLowerASCII(b[i]));
35 if (lower_a < lower_b)
36 return -1;
37 if (lower_a > lower_b)
38 return 1;
39 i++;
40 }
41
42 // End of one string hit before finding a different character. Expect the
43 // common case to be "strings equal" at this point so check that first.
44 if (a.length() == b.length())
45 return 0;
46
47 if (a.length() < b.length())
48 return -1;
49 return 1;
50 }
51
52 template <typename CharT, typename CharU>
EqualsCaseInsensitiveASCIIT(BasicStringPiece<CharT> a,BasicStringPiece<CharU> b)53 inline bool EqualsCaseInsensitiveASCIIT(BasicStringPiece<CharT> a,
54 BasicStringPiece<CharU> b) {
55 return ranges::equal(a, b, [](auto lhs, auto rhs) {
56 return ToLowerASCII(lhs) == ToLowerASCII(rhs);
57 });
58 }
59
60 } // namespace base::internal
61
62 #endif // BASE_STRINGS_STRING_UTIL_INTERNAL_H_
63