Line data Source code
1 : //
2 : // Copyright (c) 2021 Vinnie Falco (vinnie dot falco at gmail dot 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_GRAMMAR_STRING_TOKEN_HPP
11 : #define BOOST_URL_GRAMMAR_STRING_TOKEN_HPP
12 :
13 : #include <boost/url/detail/config.hpp>
14 : #include <boost/core/detail/string_view.hpp>
15 : #include <boost/url/detail/except.hpp>
16 : #include <memory>
17 : #include <string>
18 :
19 : namespace boost {
20 : namespace urls {
21 : namespace string_token {
22 :
23 : /** Base class for string tokens, and algorithm parameters
24 :
25 : This abstract interface provides a means
26 : for an algorithm to generically obtain a
27 : modifiable, contiguous character buffer
28 : of prescribed size. As the author of an
29 : algorithm simply declare an rvalue
30 : reference as a parameter type.
31 :
32 : <br>
33 :
34 : Instances of this type are intended only
35 : to be used once and then destroyed.
36 :
37 : @par Example
38 : The declared function accepts any
39 : temporary instance of `arg` to be
40 : used for writing:
41 : @code
42 : void algorithm( string_token::arg&& dest );
43 : @endcode
44 :
45 : To implement the interface for your type
46 : or use-case, derive from the class and
47 : implement the prepare function.
48 : */
49 : struct arg
50 : {
51 : /** Return a modifiable character buffer
52 :
53 : This function attempts to obtain a
54 : character buffer with space for at
55 : least `n` characters. Upon success,
56 : a pointer to the beginning of the
57 : buffer is returned. Ownership is not
58 : transferred; the caller should not
59 : attempt to free the storage. The
60 : buffer shall remain valid until
61 : `this` is destroyed.
62 :
63 : @note
64 : This function may only be called once.
65 : After invoking the function, the only
66 : valid operation is destruction.
67 : */
68 : virtual char* prepare(std::size_t n) = 0;
69 :
70 : /// Virtual destructor
71 3372 : virtual ~arg() = default;
72 :
73 : /// Default constructor
74 3372 : arg() = default;
75 :
76 : /// Default move constructor
77 : arg(arg&&) = default;
78 :
79 : /// Deleted copy constructor
80 : arg(arg const&) = delete;
81 :
82 : /// Deleted move assignment
83 : arg& operator=(arg&&) = delete;
84 :
85 : /// Deleted copy assignment
86 : arg& operator=(arg const&) = delete;
87 : };
88 :
89 : //------------------------------------------------
90 :
91 : /** Metafunction returning true if T is a StringToken
92 : */
93 : #ifdef BOOST_URL_DOCS
94 : template<class T>
95 : using is_token = __see_below__;
96 : #else
97 : namespace see_below {
98 : /** Metafunction returning true if T is a StringToken
99 : */
100 : template<class T, class = void>
101 : struct is_token : std::false_type {};
102 :
103 : /** Metafunction returning true if T is a StringToken
104 : */
105 : template<class T>
106 : struct is_token<T, void_t<
107 : decltype(std::declval<T&>().prepare(
108 : std::declval<std::size_t>())),
109 : decltype(std::declval<T&>().result())
110 : > > : std::integral_constant<bool,
111 : std::is_convertible<decltype(
112 : std::declval<T&>().result()),
113 : typename T::result_type>::value &&
114 : std::is_same<decltype(
115 : std::declval<T&>().prepare(0)),
116 : char*>::value &&
117 : std::is_base_of<arg, T>::value &&
118 : std::is_convertible<T const volatile*,
119 : arg const volatile*>::value
120 : >
121 : {
122 : };
123 : } // see_below
124 :
125 : /** Metafunction returning true if T is a StringToken
126 : */
127 : template<class T>
128 : using is_token = see_below::is_token<T>;
129 : #endif
130 :
131 : //------------------------------------------------
132 :
133 : /** A token for returning a plain string
134 : */
135 : #ifdef BOOST_URL_DOCS
136 : using return_string = __implementation_defined__;
137 : #else
138 : namespace implementation_defined {
139 : struct return_string
140 : : arg
141 : {
142 : using result_type = std::string;
143 :
144 : char*
145 3028 : prepare(std::size_t n) override
146 : {
147 3028 : s_.resize(n);
148 3028 : return &s_[0];
149 : }
150 :
151 : result_type
152 3028 : result() noexcept
153 : {
154 3028 : return std::move(s_);
155 : }
156 :
157 : private:
158 : result_type s_;
159 : };
160 : } // implementation_defined
161 :
162 : /** A token for returning a plain string
163 : */
164 : using return_string = implementation_defined::return_string;
165 : #endif
166 :
167 : //------------------------------------------------
168 :
169 : /** A token for appending to a plain string
170 : */
171 : #ifdef BOOST_URL_DOCS
172 : template<
173 : class Allocator =
174 : std::allocator<char>>
175 : __implementation_defined__
176 : append_to(
177 : std::basic_string<
178 : char,
179 : std::char_traits<char>,
180 : Allocator>& s);
181 : #else
182 : namespace implementation_defined {
183 : template<class Alloc>
184 : struct append_to_t
185 : : arg
186 : {
187 : using string_type = std::basic_string<
188 : char, std::char_traits<char>,
189 : Alloc>;
190 :
191 : using result_type = string_type&;
192 :
193 : explicit
194 3 : append_to_t(
195 : string_type& s) noexcept
196 3 : : s_(s)
197 : {
198 3 : }
199 :
200 : char*
201 3 : prepare(std::size_t n) override
202 : {
203 3 : std::size_t n0 = s_.size();
204 3 : if(n > s_.max_size() - n0)
205 0 : urls::detail::throw_length_error();
206 3 : s_.resize(n0 + n);
207 3 : return &s_[n0];
208 : }
209 :
210 : result_type
211 3 : result() noexcept
212 : {
213 3 : return s_;
214 : }
215 :
216 : private:
217 : string_type& s_;
218 : };
219 : } // implementation_defined
220 :
221 : /** Create a token for appending to a plain string
222 : */
223 : template<
224 : class Alloc =
225 : std::allocator<char>>
226 : implementation_defined::append_to_t<Alloc>
227 3 : append_to(
228 : std::basic_string<
229 : char,
230 : std::char_traits<char>,
231 : Alloc>& s)
232 : {
233 3 : return implementation_defined::append_to_t<Alloc>(s);
234 : }
235 : #endif
236 :
237 : //------------------------------------------------
238 :
239 : /** A token for assigning to a plain string
240 : */
241 : #ifdef BOOST_URL_DOCS
242 : template<
243 : class Allocator =
244 : std::allocator<char>>
245 : __implementation_defined__
246 : assign_to(
247 : std::basic_string<
248 : char,
249 : std::char_traits<char>,
250 : Allocator>& s);
251 : #else
252 : namespace implementation_defined {
253 : template<class Alloc>
254 : struct assign_to_t
255 : : arg
256 : {
257 : using string_type = std::basic_string<
258 : char, std::char_traits<char>,
259 : Alloc>;
260 :
261 : using result_type = string_type&;
262 :
263 : explicit
264 337 : assign_to_t(
265 : string_type& s) noexcept
266 337 : : s_(s)
267 : {
268 337 : }
269 :
270 : char*
271 337 : prepare(std::size_t n) override
272 : {
273 337 : s_.resize(n);
274 337 : return &s_[0];
275 : }
276 :
277 : result_type
278 337 : result() noexcept
279 : {
280 337 : return s_;
281 : }
282 :
283 : private:
284 : string_type& s_;
285 : };
286 : } // implementation_defined
287 :
288 : /** A token for assigning to a plain string
289 : */
290 : template<
291 : class Alloc =
292 : std::allocator<char>>
293 : implementation_defined::assign_to_t<Alloc>
294 337 : assign_to(
295 : std::basic_string<
296 : char,
297 : std::char_traits<char>,
298 : Alloc>& s)
299 : {
300 337 : return implementation_defined::assign_to_t<Alloc>(s);
301 : }
302 : #endif
303 :
304 : //------------------------------------------------
305 :
306 : /** A token for producing a durable core::string_view from a temporary string
307 : */
308 : #ifdef BOOST_URL_DOCS
309 : template<
310 : class Allocator =
311 : std::allocator<char>>
312 : __implementation_defined__
313 : preserve_size(
314 : std::basic_string<
315 : char,
316 : std::char_traits<char>,
317 : Allocator>& s);
318 : #else
319 : namespace implementation_defined {
320 : template<class Alloc>
321 : struct preserve_size_t
322 : : arg
323 : {
324 : using result_type = core::string_view;
325 :
326 : using string_type = std::basic_string<
327 : char, std::char_traits<char>,
328 : Alloc>;
329 :
330 : explicit
331 4 : preserve_size_t(
332 : string_type& s) noexcept
333 4 : : s_(s)
334 : {
335 4 : }
336 :
337 : char*
338 4 : prepare(std::size_t n) override
339 : {
340 4 : n_ = n;
341 : // preserve size() to
342 : // avoid value-init
343 4 : if(s_.size() < n)
344 2 : s_.resize(n);
345 4 : return &s_[0];
346 : }
347 :
348 : result_type
349 4 : result() noexcept
350 : {
351 4 : return core::string_view(
352 8 : s_.data(), n_);
353 : }
354 :
355 : private:
356 : string_type& s_;
357 : std::size_t n_ = 0;
358 : };
359 : } // implementation_defined
360 :
361 : /** A token for producing a durable core::string_view from a temporary string
362 : */
363 : template<
364 : class Alloc =
365 : std::allocator<char>>
366 : implementation_defined::preserve_size_t<Alloc>
367 4 : preserve_size(
368 : std::basic_string<
369 : char,
370 : std::char_traits<char>,
371 : Alloc>& s)
372 : {
373 4 : return implementation_defined::preserve_size_t<Alloc>(s);
374 : }
375 : #endif
376 :
377 : } // string_token
378 :
379 : namespace grammar {
380 : namespace string_token = ::boost::urls::string_token;
381 : } // grammar
382 :
383 : } // urls
384 : } // boost
385 :
386 : #endif
|