src/grammar/ci_string.cpp

98.4% Lines (63/64) 100.0% List of functions (4/4)
ci_string.cpp
f(x) Functions (4)
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/url
8 //
9
10
11 #include <boost/url/detail/config.hpp>
12 #include <boost/url/grammar/ci_string.hpp>
13
14 // FNV-1a (in ci_digest below) relies on modular multiplication
15 // of unsigned values, which Clang's -fsanitize=integer flags as
16 // overflow. Suppress the check for that function only. GCC has
17 // no equivalent sanitizer (it does not flag unsigned overflow),
18 // so the annotation is Clang-only — applying it on GCC produces
19 // "attribute directive ignored" under -Werror=attributes.
20 #if defined(__clang__) && defined(__has_attribute)
21 # if __has_attribute(no_sanitize)
22 # define BOOST_URL_NO_SANITIZE_INT_OVERFLOW \
23 __attribute__((no_sanitize("unsigned-integer-overflow")))
24 # endif
25 #endif
26 #ifndef BOOST_URL_NO_SANITIZE_INT_OVERFLOW
27 # define BOOST_URL_NO_SANITIZE_INT_OVERFLOW
28 #endif
29
30 namespace boost {
31 namespace urls {
32 namespace grammar {
33
34 namespace detail {
35
36 //------------------------------------------------
37
38 // https://lemire.me/blog/2020/04/30/for-case-insensitive-string-comparisons-avoid-char-by-char-functions/
39 // https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2020/04/30/tolower.cpp
40
41 bool
42 8x ci_is_equal(
43 core::string_view s0,
44 core::string_view s1) noexcept
45 {
46 8x auto n = s0.size();
47 8x auto p1 = s0.data();
48 8x auto p2 = s1.data();
49 char a, b;
50 // fast loop
51 13x while(n != 0)
52 {
53 10x --n;
54 10x a = *p1++;
55 10x b = *p2++;
56 10x if(a != b)
57 5x goto slow;
58 }
59 3x return true;
60 for(;;)
61 {
62 8x a = *p1++;
63 8x b = *p2++;
64 13x slow:
65 26x if( to_lower(a) !=
66 13x to_lower(b))
67 return false;
68 13x if(n == 0)
69 5x break;
70 8x --n;
71 }
72 5x return true;
73 }
74
75 //------------------------------------------------
76
77 bool
78 5x ci_is_less(
79 core::string_view s0,
80 core::string_view s1) noexcept
81 {
82 5x auto p1 = s0.data();
83 5x auto p2 = s1.data();
84 5x auto n = s0.size() < s1.size()
85 5x ? s0.size() : s1.size();
86 18x while(n != 0)
87 {
88 15x --n;
89 15x auto c1 = to_lower(*p1++);
90 15x auto c2 = to_lower(*p2++);
91 15x if(c1 != c2)
92 2x return c1 < c2;
93 }
94 3x return s0.size() < s1.size();
95 }
96
97 } // detail
98
99 //------------------------------------------------
100
101 int
102 21x ci_compare(
103 core::string_view s0,
104 core::string_view s1) noexcept
105 {
106 int bias;
107 std::size_t n;
108 42x if( s0.size() <
109 21x s1.size())
110 {
111 2x bias = -1;
112 2x n = s0.size();
113 }
114 else
115 {
116 38x if( s0.size() >
117 19x s1.size())
118 2x bias = 1;
119 else
120 17x bias = 0;
121 19x n = s1.size();
122 }
123 21x auto it0 = s0.data();
124 21x auto it1 = s1.data();
125 38x while(n != 0)
126 {
127 29x --n;
128 auto c0 =
129 29x to_lower(*it0++);
130 auto c1 =
131 29x to_lower(*it1++);
132 29x if(c0 == c1)
133 17x continue;
134 12x if(c0 < c1)
135 8x return -1;
136 4x return 1;
137 }
138 9x return bias;
139 }
140
141 //------------------------------------------------
142
143 BOOST_URL_NO_SANITIZE_INT_OVERFLOW
144 std::size_t
145 18x ci_digest(
146 core::string_view s) noexcept
147 {
148 // Only 4 and 8 byte sizes are supported
149 static_assert(
150 sizeof(std::size_t) == 4 ||
151 sizeof(std::size_t) == 8, "");
152 18x constexpr std::size_t prime = (
153 sizeof(std::size_t) == 8) ?
154 0x100000001B3ULL :
155 0x01000193UL;
156 18x constexpr std::size_t hash0 = (
157 sizeof(std::size_t) == 8) ?
158 0xcbf29ce484222325ULL :
159 0x811C9DC5UL;
160 18x auto hash = hash0;
161 18x auto p = s.data();
162 18x auto n = s.size();
163 56x for(; n != 0; --n, ++p)
164 {
165 // VFALCO NOTE Consider using a lossy
166 // to_lower which works 4 or 8 chars at a time.
167 38x hash = (to_lower(*p) ^ hash) * prime;
168 }
169 18x return hash;
170 }
171
172 } // grammar
173 } // urls
174 } // boost
175
176