Line data Source code
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 632 : , 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 19 : named_arg(core::string_view n, T const& v)
95 19 : : name(n)
96 19 : , value(v)
97 19 : {}
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 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 144 : make_format_args( Args&&... args )
191 : {
192 144 : 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 144 : format_args( std::array<format_arg, N> const& store ) noexcept
211 144 : : p_(store.data())
212 144 : , n_(store.size())
213 144 : {}
214 :
215 : format_arg
216 442 : get( std::size_t i ) const noexcept
217 : {
218 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 132 : for (std::size_t i = 0; i < n_; ++i)
227 : {
228 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 : namespace see_below {
336 : using format_arg = detail::format_arg;
337 : }
338 : namespace implementation_defined {
339 : template <class T>
340 : using named_arg = detail::named_arg<T>;
341 : }
342 : } // url
343 : } // boost
344 :
345 :
346 : #include <boost/url/detail/impl/format_args.hpp>
347 :
348 : #endif
|