src/grammar/ci_string.cpp

98.3% Lines (58/59) 100.0% Functions (4/4)
src/grammar/ci_string.cpp
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 namespace boost {
15 namespace urls {
16 namespace grammar {
17
18 namespace detail {
19
20 //------------------------------------------------
21
22 // https://lemire.me/blog/2020/04/30/for-case-insensitive-string-comparisons-avoid-char-by-char-functions/
23 // https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2020/04/30/tolower.cpp
24
25 bool
26 8 ci_is_equal(
27 core::string_view s0,
28 core::string_view s1) noexcept
29 {
30 8 auto n = s0.size();
31 8 auto p1 = s0.data();
32 8 auto p2 = s1.data();
33 char a, b;
34 // fast loop
35 13 while(n--)
36 {
37 10 a = *p1++;
38 10 b = *p2++;
39 10 if(a != b)
40 5 goto slow;
41 }
42 3 return true;
43 do
44 {
45 8 a = *p1++;
46 8 b = *p2++;
47 13 slow:
48 26 if( to_lower(a) !=
49 13 to_lower(b))
50 return false;
51 }
52 13 while(n--);
53 5 return true;
54 }
55
56 //------------------------------------------------
57
58 bool
59 5 ci_is_less(
60 core::string_view s0,
61 core::string_view s1) noexcept
62 {
63 5 auto p1 = s0.data();
64 5 auto p2 = s1.data();
65 5 auto n = s0.size() < s1.size()
66 5 ? s0.size() : s1.size();
67 18 while(n--)
68 {
69 15 auto c1 = to_lower(*p1++);
70 15 auto c2 = to_lower(*p2++);
71 15 if(c1 != c2)
72 2 return c1 < c2;
73 }
74 3 return s0.size() < s1.size();
75 }
76
77 } // detail
78
79 //------------------------------------------------
80
81 int
82 21 ci_compare(
83 core::string_view s0,
84 core::string_view s1) noexcept
85 {
86 int bias;
87 std::size_t n;
88 42 if( s0.size() <
89 21 s1.size())
90 {
91 2 bias = -1;
92 2 n = s0.size();
93 }
94 else
95 {
96 38 if( s0.size() >
97 19 s1.size())
98 2 bias = 1;
99 else
100 17 bias = 0;
101 19 n = s1.size();
102 }
103 21 auto it0 = s0.data();
104 21 auto it1 = s1.data();
105 38 while(n--)
106 {
107 auto c0 =
108 29 to_lower(*it0++);
109 auto c1 =
110 29 to_lower(*it1++);
111 29 if(c0 == c1)
112 17 continue;
113 12 if(c0 < c1)
114 8 return -1;
115 4 return 1;
116 }
117 9 return bias;
118 }
119
120 //------------------------------------------------
121
122 std::size_t
123 18 ci_digest(
124 core::string_view s) noexcept
125 {
126 // Only 4 and 8 byte sizes are supported
127 static_assert(
128 sizeof(std::size_t) == 4 ||
129 sizeof(std::size_t) == 8, "");
130 18 constexpr std::size_t prime = (
131 sizeof(std::size_t) == 8) ?
132 0x100000001B3ULL :
133 0x01000193UL;
134 18 constexpr std::size_t hash0 = (
135 sizeof(std::size_t) == 8) ?
136 0xcbf29ce484222325ULL :
137 0x811C9DC5UL;
138 18 auto hash = hash0;
139 18 auto p = s.data();
140 18 auto n = s.size();
141 56 for(;n--;++p)
142 {
143 // VFALCO NOTE Consider using a lossy
144 // to_lower which works 4 or 8 chars at a time.
145 38 hash = (to_lower(*p) ^ hash) * prime;
146 }
147 18 return hash;
148 }
149
150 } // grammar
151 } // urls
152 } // boost
153
154