Line data 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 7 : ci_is_equal( 27 : core::string_view s0, 28 : core::string_view s1) noexcept 29 : { 30 7 : auto n = s0.size(); 31 7 : auto p1 = s0.data(); 32 7 : auto p2 = s1.data(); 33 : char a, b; 34 : // fast loop 35 11 : while(n--) 36 : { 37 8 : a = *p1++; 38 8 : b = *p2++; 39 8 : if(a != b) 40 4 : goto slow; 41 : } 42 3 : return true; 43 12 : slow: 44 8 : do 45 : { 46 24 : if( to_lower(a) != 47 12 : to_lower(b)) 48 0 : return false; 49 12 : a = *p1++; 50 12 : b = *p2++; 51 : } 52 12 : while(n--); 53 4 : 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 18 : for(auto n = s0.size();n--;) 66 : { 67 15 : auto c1 = to_lower(*p1++); 68 15 : auto c2 = to_lower(*p2++); 69 15 : if(c1 != c2) 70 2 : return c1 < c2; 71 : } 72 : // equal 73 3 : return false; 74 : } 75 : 76 : } // detail 77 : 78 : //------------------------------------------------ 79 : 80 : int 81 21 : ci_compare( 82 : core::string_view s0, 83 : core::string_view s1) noexcept 84 : { 85 : int bias; 86 : std::size_t n; 87 42 : if( s0.size() < 88 21 : s1.size()) 89 : { 90 2 : bias = -1; 91 2 : n = s0.size(); 92 : } 93 : else 94 : { 95 38 : if( s0.size() > 96 19 : s1.size()) 97 2 : bias = 1; 98 : else 99 17 : bias = 0; 100 19 : n = s1.size(); 101 : } 102 21 : auto it0 = s0.data(); 103 21 : auto it1 = s1.data(); 104 38 : while(n--) 105 : { 106 : auto c0 = 107 29 : to_lower(*it0++); 108 : auto c1 = 109 29 : to_lower(*it1++); 110 29 : if(c0 == c1) 111 17 : continue; 112 12 : if(c0 < c1) 113 8 : return -1; 114 4 : return 1; 115 : } 116 9 : return bias; 117 : } 118 : 119 : //------------------------------------------------ 120 : 121 : std::size_t 122 18 : ci_digest( 123 : core::string_view s) noexcept 124 : { 125 : // Only 4 and 8 byte sizes are supported 126 : static_assert( 127 : sizeof(std::size_t) == 4 || 128 : sizeof(std::size_t) == 8, ""); 129 18 : constexpr std::size_t prime = ( 130 : sizeof(std::size_t) == 8) ? 131 : 0x100000001B3ULL : 132 : 0x01000193UL; 133 18 : constexpr std::size_t hash0 = ( 134 : sizeof(std::size_t) == 8) ? 135 : 0xcbf29ce484222325ULL : 136 : 0x811C9DC5UL; 137 18 : auto hash = hash0; 138 18 : auto p = s.data(); 139 18 : auto n = s.size(); 140 56 : for(;n--;++p) 141 : { 142 : // VFALCO NOTE Consider using a lossy 143 : // to_lower which works 4 or 8 chars at a time. 144 38 : hash = (to_lower(*p) ^ hash) * prime; 145 : } 146 18 : return hash; 147 : } 148 : 149 : } // grammar 150 : } // urls 151 : } // boost 152 :