1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/boostorg/url
7  
// Official repository: https://github.com/boostorg/url
8  
//
8  
//
9  

9  

10  

10  

11  
#include <boost/url/detail/config.hpp>
11  
#include <boost/url/detail/config.hpp>
12  
#include <boost/url/grammar/ci_string.hpp>
12  
#include <boost/url/grammar/ci_string.hpp>
13  

13  

14  
namespace boost {
14  
namespace boost {
15  
namespace urls {
15  
namespace urls {
16  
namespace grammar {
16  
namespace grammar {
17  

17  

18  
namespace detail {
18  
namespace detail {
19  

19  

20  
//------------------------------------------------
20  
//------------------------------------------------
21  

21  

22  
// https://lemire.me/blog/2020/04/30/for-case-insensitive-string-comparisons-avoid-char-by-char-functions/
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
23  
// https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2020/04/30/tolower.cpp
24  

24  

25  
bool
25  
bool
26  
ci_is_equal(
26  
ci_is_equal(
27  
    core::string_view s0,
27  
    core::string_view s0,
28  
    core::string_view s1) noexcept
28  
    core::string_view s1) noexcept
29  
{
29  
{
30  
    auto n = s0.size();
30  
    auto n = s0.size();
31  
    auto p1 = s0.data();
31  
    auto p1 = s0.data();
32  
    auto p2 = s1.data();
32  
    auto p2 = s1.data();
33  
    char a, b;
33  
    char a, b;
34  
    // fast loop
34  
    // fast loop
35  
    while(n--)
35  
    while(n--)
36  
    {
36  
    {
37  
        a = *p1++;
37  
        a = *p1++;
38  
        b = *p2++;
38  
        b = *p2++;
39  
        if(a != b)
39  
        if(a != b)
40  
            goto slow;
40  
            goto slow;
41  
    }
41  
    }
42  
    return true;
42  
    return true;
43  
    do
43  
    do
44  
    {
44  
    {
45  
        a = *p1++;
45  
        a = *p1++;
46  
        b = *p2++;
46  
        b = *p2++;
47  
    slow:
47  
    slow:
48  
        if( to_lower(a) !=
48  
        if( to_lower(a) !=
49  
            to_lower(b))
49  
            to_lower(b))
50  
            return false;
50  
            return false;
51  
    }
51  
    }
52  
    while(n--);
52  
    while(n--);
53  
    return true;
53  
    return true;
54  
}
54  
}
55  

55  

56  
//------------------------------------------------
56  
//------------------------------------------------
57  

57  

58  
bool
58  
bool
59  
ci_is_less(
59  
ci_is_less(
60  
    core::string_view s0,
60  
    core::string_view s0,
61  
    core::string_view s1) noexcept
61  
    core::string_view s1) noexcept
62  
{
62  
{
63  
    auto p1 = s0.data();
63  
    auto p1 = s0.data();
64  
    auto p2 = s1.data();
64  
    auto p2 = s1.data();
65  
    for(auto n = s0.size();n--;)
65  
    for(auto n = s0.size();n--;)
66  
    {
66  
    {
67  
        auto c1 = to_lower(*p1++);
67  
        auto c1 = to_lower(*p1++);
68  
        auto c2 = to_lower(*p2++);
68  
        auto c2 = to_lower(*p2++);
69  
        if(c1 != c2)
69  
        if(c1 != c2)
70  
            return c1 < c2;
70  
            return c1 < c2;
71  
    }
71  
    }
72  
    // equal
72  
    // equal
73  
    return false;
73  
    return false;
74  
}
74  
}
75  

75  

76  
} // detail
76  
} // detail
77  

77  

78  
//------------------------------------------------
78  
//------------------------------------------------
79  

79  

80  
int
80  
int
81  
ci_compare(
81  
ci_compare(
82  
    core::string_view s0,
82  
    core::string_view s0,
83  
    core::string_view s1) noexcept
83  
    core::string_view s1) noexcept
84  
{
84  
{
85  
    int bias;
85  
    int bias;
86  
    std::size_t n;
86  
    std::size_t n;
87  
    if( s0.size() <
87  
    if( s0.size() <
88  
        s1.size())
88  
        s1.size())
89  
    {
89  
    {
90  
        bias = -1;
90  
        bias = -1;
91  
        n = s0.size();
91  
        n = s0.size();
92  
    }
92  
    }
93  
    else
93  
    else
94  
    {
94  
    {
95  
        if( s0.size() >
95  
        if( s0.size() >
96  
            s1.size())
96  
            s1.size())
97  
            bias = 1;
97  
            bias = 1;
98  
        else
98  
        else
99  
            bias = 0;
99  
            bias = 0;
100  
        n = s1.size();
100  
        n = s1.size();
101  
    }
101  
    }
102  
    auto it0 = s0.data();
102  
    auto it0 = s0.data();
103  
    auto it1 = s1.data();
103  
    auto it1 = s1.data();
104  
    while(n--)
104  
    while(n--)
105  
    {
105  
    {
106  
        auto c0 =
106  
        auto c0 =
107  
            to_lower(*it0++);
107  
            to_lower(*it0++);
108  
        auto c1 =
108  
        auto c1 =
109  
            to_lower(*it1++);
109  
            to_lower(*it1++);
110  
        if(c0 == c1)
110  
        if(c0 == c1)
111  
            continue;
111  
            continue;
112  
        if(c0 < c1)
112  
        if(c0 < c1)
113  
            return -1;
113  
            return -1;
114  
        return 1;
114  
        return 1;
115  
    }
115  
    }
116  
    return bias;
116  
    return bias;
117  
}
117  
}
118  

118  

119  
//------------------------------------------------
119  
//------------------------------------------------
120  

120  

121  
std::size_t
121  
std::size_t
122  
ci_digest(
122  
ci_digest(
123  
    core::string_view s) noexcept
123  
    core::string_view s) noexcept
124  
{
124  
{
125  
    // Only 4 and 8 byte sizes are supported
125  
    // Only 4 and 8 byte sizes are supported
126  
    static_assert(
126  
    static_assert(
127  
        sizeof(std::size_t) == 4 ||
127  
        sizeof(std::size_t) == 4 ||
128  
        sizeof(std::size_t) == 8, "");
128  
        sizeof(std::size_t) == 8, "");
129  
    constexpr std::size_t prime = (
129  
    constexpr std::size_t prime = (
130  
        sizeof(std::size_t) == 8) ?
130  
        sizeof(std::size_t) == 8) ?
131  
            0x100000001B3ULL :
131  
            0x100000001B3ULL :
132  
            0x01000193UL;
132  
            0x01000193UL;
133  
    constexpr std::size_t hash0 = (
133  
    constexpr std::size_t hash0 = (
134  
        sizeof(std::size_t) == 8) ?
134  
        sizeof(std::size_t) == 8) ?
135  
            0xcbf29ce484222325ULL :
135  
            0xcbf29ce484222325ULL :
136  
            0x811C9DC5UL;
136  
            0x811C9DC5UL;
137  
    auto hash = hash0;
137  
    auto hash = hash0;
138  
    auto p = s.data();
138  
    auto p = s.data();
139  
    auto n = s.size();
139  
    auto n = s.size();
140  
    for(;n--;++p)
140  
    for(;n--;++p)
141  
    {
141  
    {
142  
        // VFALCO NOTE Consider using a lossy
142  
        // VFALCO NOTE Consider using a lossy
143  
        // to_lower which works 4 or 8 chars at a time.
143  
        // to_lower which works 4 or 8 chars at a time.
144  
        hash = (to_lower(*p) ^ hash) * prime;
144  
        hash = (to_lower(*p) ^ hash) * prime;
145  
    }
145  
    }
146  
    return hash;
146  
    return hash;
147  
}
147  
}
148  

148  

149  
} // grammar
149  
} // grammar
150  
} // urls
150  
} // urls
151  
} // boost
151  
} // boost
152  

152