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  
    auto n = s0.size() < s1.size()
65  
    auto n = s0.size() < s1.size()
66  
        ? s0.size() : s1.size();
66  
        ? s0.size() : s1.size();
67  
    while(n--)
67  
    while(n--)
68  
    {
68  
    {
69  
        auto c1 = to_lower(*p1++);
69  
        auto c1 = to_lower(*p1++);
70  
        auto c2 = to_lower(*p2++);
70  
        auto c2 = to_lower(*p2++);
71  
        if(c1 != c2)
71  
        if(c1 != c2)
72  
            return c1 < c2;
72  
            return c1 < c2;
73  
    }
73  
    }
74  
    return s0.size() < s1.size();
74  
    return s0.size() < s1.size();
75  
}
75  
}
76  

76  

77  
} // detail
77  
} // detail
78  

78  

79  
//------------------------------------------------
79  
//------------------------------------------------
80  

80  

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

119  

120  
//------------------------------------------------
120  
//------------------------------------------------
121  

121  

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

149  

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

153