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