1  
//
1  
//
2  
// Copyright (c) 2022 Alan de Freitas (alandefreitas at gmail dot com)
2  
// Copyright (c) 2022 Alan de Freitas (alandefreitas at gmail dot 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  
#ifndef BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
10  
#ifndef BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
11  
#define BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
11  
#define BOOST_URL_GRAMMAR_IMPL_UNSIGNED_RULE_HPP
12  

12  

13  
#include <boost/url/grammar/error.hpp>
13  
#include <boost/url/grammar/error.hpp>
14  
#include <boost/url/grammar/digit_chars.hpp>
14  
#include <boost/url/grammar/digit_chars.hpp>
15  
#include <algorithm> // VFALCO grr..
15  
#include <algorithm> // VFALCO grr..
16  

16  

17  
namespace boost {
17  
namespace boost {
18  
namespace urls {
18  
namespace urls {
19  
namespace grammar {
19  
namespace grammar {
20  

20  

21  
template<class U>
21  
template<class U>
 
22 +
BOOST_URL_CXX14_CONSTEXPR
22  
auto
23  
auto
23  
unsigned_rule<U>::
24  
unsigned_rule<U>::
24  
parse(
25  
parse(
25  
    char const*& it,
26  
    char const*& it,
26  
    char const* end
27  
    char const* end
27  
        ) const noexcept ->
28  
        ) const noexcept ->
28  
    system::result<value_type>
29  
    system::result<value_type>
29  
{
30  
{
30  
    if(it == end)
31  
    if(it == end)
31  
    {
32  
    {
32  
        // end
33  
        // end
33 -
        BOOST_URL_RETURN_EC(
34 +
        BOOST_URL_CONSTEXPR_RETURN_EC(
34  
            error::mismatch);
35  
            error::mismatch);
35  
    }
36  
    }
36  
    if(*it == '0')
37  
    if(*it == '0')
37  
    {
38  
    {
38  
        ++it;
39  
        ++it;
39  
        if( it == end ||
40  
        if( it == end ||
40  
            ! digit_chars(*it))
41  
            ! digit_chars(*it))
41  
        {
42  
        {
42  
            return U(0);
43  
            return U(0);
43  
        }
44  
        }
44  
        // bad leading zero
45  
        // bad leading zero
45 -
        BOOST_URL_RETURN_EC(
46 +
        BOOST_URL_CONSTEXPR_RETURN_EC(
46  
            error::invalid);
47  
            error::invalid);
47  
    }
48  
    }
48  
    if(! digit_chars(*it))
49  
    if(! digit_chars(*it))
49  
    {
50  
    {
50  
        // expected digit
51  
        // expected digit
51 -
        BOOST_URL_RETURN_EC(
52 +
        BOOST_URL_CONSTEXPR_RETURN_EC(
52  
            error::mismatch);
53  
            error::mismatch);
53  
    }
54  
    }
54 -
    static constexpr U Digits10 =
55 +
    constexpr U Digits10 =
55  
        std::numeric_limits<
56  
        std::numeric_limits<
56  
            U>::digits10;
57  
            U>::digits10;
57 -
    static constexpr U ten = 10;
58 +
    constexpr U ten = 10;
58 -
    char const* safe_end;
59 +
    char const* safe_end = nullptr;
59  
    if(static_cast<std::size_t>(
60  
    if(static_cast<std::size_t>(
60  
            end - it) >= Digits10)
61  
            end - it) >= Digits10)
61  
        safe_end = it + Digits10;
62  
        safe_end = it + Digits10;
62  
    else
63  
    else
63  
        safe_end = end;
64  
        safe_end = end;
64  
    U u = *it - '0';
65  
    U u = *it - '0';
65  
    ++it;
66  
    ++it;
66  
    while(it != safe_end &&
67  
    while(it != safe_end &&
67  
        digit_chars(*it))
68  
        digit_chars(*it))
68  
    {
69  
    {
69  
        char const dig = *it - '0';
70  
        char const dig = *it - '0';
70  
        u = u * ten + dig;
71  
        u = u * ten + dig;
71  
        ++it;
72  
        ++it;
72  
    }
73  
    }
73  
    if( it != end &&
74  
    if( it != end &&
74  
        digit_chars(*it))
75  
        digit_chars(*it))
75  
    {
76  
    {
76 -
        static constexpr U Max = (
77 +
        constexpr U Max = (
77  
            std::numeric_limits<
78  
            std::numeric_limits<
78  
                U>::max)();
79  
                U>::max)();
79 -
        static constexpr
80 +
        constexpr
80  
            auto div = (Max / ten);
81  
            auto div = (Max / ten);
81 -
        static constexpr
82 +
        constexpr
82  
            char rem = (Max % ten);
83  
            char rem = (Max % ten);
83  
        char const dig = *it - '0';
84  
        char const dig = *it - '0';
84  
        if( u > div || (
85  
        if( u > div || (
85  
            u == div && dig > rem))
86  
            u == div && dig > rem))
86  
        {
87  
        {
87  
            // integer overflow
88  
            // integer overflow
88 -
            BOOST_URL_RETURN_EC(
89 +
            BOOST_URL_CONSTEXPR_RETURN_EC(
89  
                error::invalid);
90  
                error::invalid);
90  
        }
91  
        }
91  
        u = u * ten + dig;
92  
        u = u * ten + dig;
92  
        ++it;
93  
        ++it;
93  
        if( it < end &&
94  
        if( it < end &&
94  
            digit_chars(*it))
95  
            digit_chars(*it))
95  
        {
96  
        {
96  
            // integer overflow
97  
            // integer overflow
97 -
            BOOST_URL_RETURN_EC(
98 +
            BOOST_URL_CONSTEXPR_RETURN_EC(
98  
                error::invalid);
99  
                error::invalid);
99  
        }
100  
        }
100  
    }
101  
    }
101  

102  

102  
    return u;
103  
    return u;
103  
}
104  
}
104  

105  

105  
} // grammar
106  
} // grammar
106  
} // urls
107  
} // urls
107  
} // boost
108  
} // boost
108  

109  

109  
#endif
110  
#endif