Line data Source code
1 : //
2 : // Copyright (c) 2021 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/cppalliance/http_proto
8 : //
9 :
10 : #ifndef BOOST_HTTP_PROTO_RFC_IMPL_LIST_RULE_HPP
11 : #define BOOST_HTTP_PROTO_RFC_IMPL_LIST_RULE_HPP
12 :
13 : #include <boost/url/grammar/parse.hpp>
14 : #include <boost/url/grammar/range_rule.hpp>
15 : #include <boost/core/empty_value.hpp>
16 : #include <type_traits>
17 :
18 : namespace boost {
19 : namespace http_proto {
20 :
21 : namespace detail {
22 :
23 : /* Peter:
24 :
25 : So, to put everything together, this is what I propose
26 :
27 : - make range2_rule that takes first and next with
28 : value types of optional<E> rather than E like the current rule
29 : - make variant_rule produce an optional<X> when otherwise
30 : the value type would have been variant<void, void, X, void>
31 : - add operators for combining the rules so that one can
32 : write *( OWS >> !literal(",") >> -( OWS >> element ) )
33 : - profit
34 : */
35 :
36 : // *( OWS "," )
37 : struct ows_comma_t
38 : {
39 : using value_type = void;
40 :
41 : auto
42 99 : parse(
43 : char const*& it,
44 : char const* end) const noexcept ->
45 : system::result<value_type>
46 : {
47 99 : auto it1 = it;
48 247 : while(it != end)
49 : {
50 : // SP / HT
51 232 : if( *it == ' ' ||
52 176 : *it == '\t')
53 : {
54 58 : ++it;
55 58 : continue;
56 : }
57 174 : if(*it != ',')
58 84 : break;
59 : // ","
60 90 : it1 = ++it;
61 : }
62 99 : it = it1;
63 99 : return {};
64 : }
65 : };
66 :
67 : constexpr ows_comma_t ows_comma{};
68 :
69 : } // detail
70 :
71 : /*
72 : #element => [ ( "," / element ) *( OWS "," [ OWS element ] ) ]
73 :
74 : #element => first *next
75 : first => [ element / ( "," *( OWS "," ) [ OWS element ] ) ]
76 : next => "" / ( 1*( OWS "," ) [ OWS element ] )
77 : */
78 :
79 : template<class Rule>
80 : struct list_rule_t<Rule>::
81 : first_rule : empty_value<Rule>
82 : {
83 : using value_type =
84 : typename Rule::value_type;
85 :
86 : constexpr
87 : explicit
88 301 : first_rule(
89 : Rule const& r) noexcept
90 : : empty_value<Rule>(
91 301 : empty_init, r)
92 : {
93 301 : }
94 :
95 : auto
96 548 : parse(
97 : char const*& it,
98 : char const* end) const ->
99 : system::result<value_type>
100 : {
101 : // first => [ element / ( "," *( OWS "," ) [ OWS element ] ) ]
102 :
103 548 : if(it == end)
104 5 : return grammar::error::end_of_range;
105 : {
106 : // element
107 543 : auto it0 = it;
108 543 : auto rv = this->get().parse(it, end);
109 543 : if(rv)
110 516 : return std::move(*rv);
111 27 : it = it0;
112 : }
113 : // ","
114 27 : if(*it != ',')
115 14 : return grammar::error::end_of_range;
116 13 : ++it;
117 : // *( OWS "," )
118 13 : detail::ows_comma.parse(it, end);
119 13 : auto it1 = it;
120 : // OWS
121 13 : it = grammar::find_if_not(
122 : it, end, detail::ws);
123 : // element
124 13 : auto rv = this->get().parse(it, end);
125 13 : if(rv)
126 6 : return std::move(*rv);
127 7 : it = it1;
128 7 : return grammar::error::end_of_range;
129 : }
130 : };
131 :
132 : template<class Rule>
133 : struct list_rule_t<Rule>::
134 : next_rule : empty_value<Rule>
135 : {
136 : using value_type =
137 : typename Rule::value_type;
138 :
139 : constexpr
140 : explicit
141 301 : next_rule(
142 : Rule const& r) noexcept
143 : : empty_value<Rule>(
144 301 : empty_init, r)
145 : {
146 301 : }
147 :
148 : auto
149 575 : parse(
150 : char const*& it,
151 : char const* end) const ->
152 : system::result<value_type>
153 : {
154 : // next => "" / ( 1*( OWS "," ) [ OWS element ] )
155 :
156 : // ""
157 575 : if(it == end)
158 489 : return grammar::error::end_of_range;
159 :
160 : // 1*( OWS "," )
161 : {
162 86 : auto it0 = it;
163 86 : detail::ows_comma.parse(it, end);
164 86 : if(it == it0)
165 7 : return grammar::error::end_of_range;
166 : }
167 79 : auto it1 = it;
168 : // OWS
169 79 : it = grammar::find_if_not(
170 : it, end, detail::ws);
171 108 : auto rv = this->get().parse(it, end);
172 79 : if(rv)
173 70 : return std::move(*rv);
174 9 : it = it1;
175 9 : return grammar::error::end_of_range;
176 : }
177 : };
178 :
179 : template<class Rule>
180 : auto
181 301 : list_rule_t<Rule>::
182 : parse(
183 : char const*& it,
184 : char const* end) const ->
185 : system::result<value_type>
186 : {
187 : return grammar::parse(it, end,
188 602 : grammar::range_rule(
189 : first_rule{this->get()},
190 : next_rule{this->get()},
191 903 : n_, m_));
192 : }
193 :
194 : } // http_proto
195 : } // boost
196 :
197 : #endif
|