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