Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2022 Alan de Freitas (alandefreitas@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/boostorg/url | ||
8 | // | ||
9 | |||
10 | #ifndef BOOST_URL_DETAIL_FORMAT_ARGS_HPP | ||
11 | #define BOOST_URL_DETAIL_FORMAT_ARGS_HPP | ||
12 | |||
13 | #include <boost/url/detail/encode.hpp> | ||
14 | #include <boost/url/grammar/lut_chars.hpp> | ||
15 | |||
16 | #include <boost/core/ignore_unused.hpp> | ||
17 | #include <array> | ||
18 | |||
19 | // This file implements functions and classes to | ||
20 | // type-erase format arguments. | ||
21 | |||
22 | namespace boost { | ||
23 | namespace urls { | ||
24 | namespace detail { | ||
25 | |||
26 | // state of the format string. It basically keeps | ||
27 | // track of where we are in the format string. | ||
28 | class format_parse_context | ||
29 | { | ||
30 | char const* begin_; | ||
31 | char const* end_; | ||
32 | std::size_t arg_id_ = 0; | ||
33 | |||
34 | public: | ||
35 | constexpr | ||
36 | 632 | format_parse_context( | |
37 | char const* first, | ||
38 | char const* last, | ||
39 | std::size_t arg_id = 0) | ||
40 | 632 | : begin_( first ) | |
41 | , end_( last ) | ||
42 | 632 | , arg_id_( arg_id ) | |
43 | 632 | {} | |
44 | |||
45 | constexpr | ||
46 | 495 | format_parse_context( | |
47 | core::string_view fmt, | ||
48 | std::size_t arg_id = 0) | ||
49 | 495 | : format_parse_context( | |
50 | fmt.data(), | ||
51 | 495 | fmt.data() + fmt.size(), | |
52 | 495 | arg_id ) | |
53 | 495 | {} | |
54 | |||
55 | constexpr | ||
56 | char const* | ||
57 | 1445 | begin() const noexcept | |
58 | { | ||
59 | 1445 | return begin_; | |
60 | } | ||
61 | |||
62 | constexpr | ||
63 | char const* | ||
64 | 971 | end() const noexcept | |
65 | { | ||
66 | 971 | return end_; | |
67 | } | ||
68 | |||
69 | BOOST_CXX14_CONSTEXPR | ||
70 | void | ||
71 | 950 | advance_to( char const* it ) | |
72 | { | ||
73 | 950 | begin_ = it; | |
74 | 950 | } | |
75 | |||
76 | std::size_t | ||
77 | 871 | next_arg_id() | |
78 | { | ||
79 | 871 | return arg_id_++; | |
80 | } | ||
81 | }; | ||
82 | |||
83 | // State of the destination string | ||
84 | class format_context; | ||
85 | class measure_context; | ||
86 | struct ignore_format {}; | ||
87 | |||
88 | template <class T> | ||
89 | struct named_arg | ||
90 | { | ||
91 | core::string_view name; | ||
92 | T const& value; | ||
93 | |||
94 | 37 | named_arg(core::string_view n, T const& v) | |
95 | : name(n) | ||
96 | 37 | , value(v) | |
97 | 37 | {} | |
98 | }; | ||
99 | |||
100 | // A type erased format argument | ||
101 | class format_arg | ||
102 | { | ||
103 | void const* arg_; | ||
104 | void (*measure_)( | ||
105 | format_parse_context&, | ||
106 | measure_context&, | ||
107 | grammar::lut_chars const&, | ||
108 | void const* ); | ||
109 | void (*fmt_)( | ||
110 | format_parse_context&, | ||
111 | format_context&, | ||
112 | grammar::lut_chars const&, | ||
113 | void const* ); | ||
114 | core::string_view name_; | ||
115 | std::size_t value_ = 0; | ||
116 | bool ignore_ = false; | ||
117 | |||
118 | template <class A> | ||
119 | static | ||
120 | void | ||
121 | measure_impl( | ||
122 | format_parse_context& pctx, | ||
123 | measure_context& mctx, | ||
124 | grammar::lut_chars const& cs, | ||
125 | void const* a ); | ||
126 | |||
127 | template <class A> | ||
128 | static | ||
129 | void | ||
130 | format_impl( | ||
131 | format_parse_context& pctx, | ||
132 | format_context& fctx, | ||
133 | grammar::lut_chars const& cs, | ||
134 | void const* a ); | ||
135 | |||
136 | public: | ||
137 | template<class A> | ||
138 | format_arg( A&& a ); | ||
139 | |||
140 | template<class A> | ||
141 | format_arg( named_arg<A>&& a ); | ||
142 | |||
143 | template<class A> | ||
144 | format_arg( core::string_view name, A&& a ); | ||
145 | |||
146 | 34 | format_arg() | |
147 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | : format_arg(ignore_format{}) |
148 | 34 | {} | |
149 | |||
150 | explicit | ||
151 | operator bool() const noexcept | ||
152 | { | ||
153 | return !ignore_; | ||
154 | } | ||
155 | |||
156 | void | ||
157 | 240 | measure( | |
158 | format_parse_context& pctx, | ||
159 | measure_context& mctx, | ||
160 | grammar::lut_chars const& cs) | ||
161 | { | ||
162 | 240 | measure_( pctx, mctx, cs, arg_ ); | |
163 | 238 | } | |
164 | |||
165 | void | ||
166 | 236 | format( | |
167 | format_parse_context& pctx, | ||
168 | format_context& fctx, | ||
169 | grammar::lut_chars const& cs ) | ||
170 | { | ||
171 | 236 | fmt_( pctx, fctx, cs, arg_ ); | |
172 | 236 | } | |
173 | |||
174 | core::string_view | ||
175 | 130 | name() const | |
176 | { | ||
177 | 130 | return name_; | |
178 | } | ||
179 | |||
180 | std::size_t | ||
181 | 28 | value() const | |
182 | { | ||
183 | 28 | return value_; | |
184 | } | ||
185 | }; | ||
186 | |||
187 | // create temp stack storage for type erased args | ||
188 | template< class... Args > | ||
189 | std::array<format_arg, sizeof...(Args)> | ||
190 | 288 | make_format_args( Args&&... args ) | |
191 | { | ||
192 | 288 | return {{ std::forward<Args>(args)... }}; | |
193 | } | ||
194 | |||
195 | // reference to an array of format_args | ||
196 | class format_args | ||
197 | { | ||
198 | format_arg const* p_{nullptr}; | ||
199 | std::size_t n_{0}; | ||
200 | |||
201 | public: | ||
202 | 3 | format_args( | |
203 | detail::format_arg const* first, | ||
204 | detail::format_arg const* last ) noexcept | ||
205 | 3 | : p_(first) | |
206 | 3 | , n_(static_cast<std::size_t>(last - first)) | |
207 | 3 | {} | |
208 | |||
209 | template < std::size_t N > | ||
210 | 288 | format_args( std::array<format_arg, N> const& store ) noexcept | |
211 | : p_(store.data()) | ||
212 | 288 | , n_(store.size()) | |
213 | 288 | {} | |
214 | |||
215 | format_arg | ||
216 | 442 | get( std::size_t i ) const noexcept | |
217 | { | ||
218 |
2/2✓ Branch 0 taken 438 times.
✓ Branch 1 taken 4 times.
|
442 | if (i < n_) |
219 | 438 | return p_[i]; | |
220 | 4 | return {}; | |
221 | } | ||
222 | |||
223 | format_arg | ||
224 | 62 | get( core::string_view name ) const noexcept | |
225 | { | ||
226 |
2/2✓ Branch 0 taken 130 times.
✓ Branch 1 taken 2 times.
|
132 | for (std::size_t i = 0; i < n_; ++i) |
227 | { | ||
228 |
2/2✓ Branch 2 taken 60 times.
✓ Branch 3 taken 70 times.
|
130 | if (p_[i].name() == name) |
229 | 60 | return p_[i]; | |
230 | } | ||
231 | 2 | return {}; | |
232 | } | ||
233 | }; | ||
234 | |||
235 | // define the format_context after format_args | ||
236 | class format_context | ||
237 | { | ||
238 | format_args args_; | ||
239 | char* out_; | ||
240 | |||
241 | public: | ||
242 | 137 | format_context( | |
243 | char* out, | ||
244 | format_args args ) | ||
245 | 137 | : args_( args ) | |
246 | 137 | , out_( out ) | |
247 | 137 | {} | |
248 | |||
249 | format_args | ||
250 | 14 | args() const noexcept | |
251 | { | ||
252 | 14 | return args_; | |
253 | } | ||
254 | |||
255 | format_arg | ||
256 | 210 | arg( std::size_t id ) const noexcept | |
257 | { | ||
258 | 210 | return args_.get( id ); | |
259 | } | ||
260 | |||
261 | format_arg | ||
262 | 26 | arg( core::string_view name ) const noexcept | |
263 | { | ||
264 | 26 | return args_.get( name ); | |
265 | } | ||
266 | |||
267 | char* | ||
268 | 939 | out() | |
269 | { | ||
270 | 939 | return out_; | |
271 | } | ||
272 | |||
273 | void | ||
274 | 939 | advance_to( char* it ) | |
275 | { | ||
276 | 939 | out_ = it; | |
277 | 939 | } | |
278 | }; | ||
279 | |||
280 | // define the measure_context after format_args | ||
281 | class measure_context | ||
282 | { | ||
283 | format_args args_; | ||
284 | std::size_t out_; | ||
285 | |||
286 | public: | ||
287 | 140 | measure_context( | |
288 | format_args args ) | ||
289 | 140 | : measure_context(0, args) | |
290 | 140 | {} | |
291 | |||
292 | 140 | measure_context( | |
293 | std::size_t out, | ||
294 | format_args args ) | ||
295 | 140 | : args_( args ) | |
296 | 140 | , out_( out ) | |
297 | 140 | {} | |
298 | |||
299 | format_args | ||
300 | 14 | args() const noexcept | |
301 | { | ||
302 | 14 | return args_; | |
303 | } | ||
304 | |||
305 | format_arg | ||
306 | 214 | arg( std::size_t id ) const noexcept | |
307 | { | ||
308 | 214 | return args_.get( id ); | |
309 | } | ||
310 | |||
311 | format_arg | ||
312 | 26 | arg( core::string_view name ) const noexcept | |
313 | { | ||
314 | 26 | return args_.get( name ); | |
315 | } | ||
316 | |||
317 | std::size_t | ||
318 | 953 | out() | |
319 | { | ||
320 | 953 | return out_; | |
321 | } | ||
322 | |||
323 | void | ||
324 | 953 | advance_to( std::size_t n ) | |
325 | { | ||
326 | 953 | out_ = n; | |
327 | 953 | } | |
328 | }; | ||
329 | |||
330 | // fwd declare the formatter | ||
331 | template <class T, class = void> | ||
332 | struct formatter; | ||
333 | |||
334 | } // detail | ||
335 | } // url | ||
336 | } // boost | ||
337 | |||
338 | #include <boost/url/detail/impl/format_args.hpp> | ||
339 | |||
340 | #endif | ||
341 |