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 : // prevent misuse
71 3372 : virtual ~arg() = default;
72 3372 : arg() = default;
73 : arg(arg&&) = default;
74 : arg(arg const&) = delete;
75 : arg& operator=(arg&&) = delete;
76 : arg& operator=(arg const&) = delete;
77 : };
78 :
79 : //------------------------------------------------
80 :
81 : /** Metafunction returning true if T is a StringToken
82 : */
83 : #ifdef BOOST_URL_DOCS
84 : template<class T>
85 : using is_token = __see_below__;
86 : #else
87 : template<class T, class = void>
88 : struct is_token : std::false_type {};
89 :
90 : template<class T>
91 : struct is_token<T, void_t<
92 : decltype(std::declval<T&>().prepare(
93 : std::declval<std::size_t>())),
94 : decltype(std::declval<T&>().result())
95 : > > : std::integral_constant<bool,
96 : std::is_convertible<decltype(
97 : std::declval<T&>().result()),
98 : typename T::result_type>::value &&
99 : std::is_same<decltype(
100 : std::declval<T&>().prepare(0)),
101 : char*>::value &&
102 : std::is_base_of<arg, T>::value &&
103 : std::is_convertible<T const volatile*,
104 : arg const volatile*>::value
105 : >
106 : {
107 : };
108 : #endif
109 :
110 : //------------------------------------------------
111 :
112 : /** A token for returning a plain string
113 : */
114 : #ifdef BOOST_URL_DOCS
115 : using return_string = __implementation_defined__;
116 : #else
117 : struct return_string
118 : : arg
119 : {
120 : using result_type = std::string;
121 :
122 : char*
123 3028 : prepare(std::size_t n) override
124 : {
125 3028 : s_.resize(n);
126 3028 : return &s_[0];
127 : }
128 :
129 : result_type
130 3028 : result() noexcept
131 : {
132 3028 : return std::move(s_);
133 : }
134 :
135 : private:
136 : result_type s_;
137 : };
138 : #endif
139 :
140 : //------------------------------------------------
141 :
142 : /** A token for appending to a plain string
143 : */
144 : #ifdef BOOST_URL_DOCS
145 : template<
146 : class Allocator =
147 : std::allocator<char>>
148 : __implementation_defined__
149 : append_to(
150 : std::basic_string<
151 : char,
152 : std::char_traits<char>,
153 : Allocator>& s);
154 : #else
155 : template<class Alloc>
156 : struct append_to_t
157 : : arg
158 : {
159 : using string_type = std::basic_string<
160 : char, std::char_traits<char>,
161 : Alloc>;
162 :
163 : using result_type = string_type&;
164 :
165 : explicit
166 3 : append_to_t(
167 : string_type& s) noexcept
168 3 : : s_(s)
169 : {
170 3 : }
171 :
172 : char*
173 3 : prepare(std::size_t n) override
174 : {
175 3 : std::size_t n0 = s_.size();
176 3 : if(n > s_.max_size() - n0)
177 0 : urls::detail::throw_length_error();
178 3 : s_.resize(n0 + n);
179 3 : return &s_[n0];
180 : }
181 :
182 : result_type
183 3 : result() noexcept
184 : {
185 3 : return s_;
186 : }
187 :
188 : private:
189 : string_type& s_;
190 : };
191 :
192 : template<
193 : class Alloc =
194 : std::allocator<char>>
195 : append_to_t<Alloc>
196 3 : append_to(
197 : std::basic_string<
198 : char,
199 : std::char_traits<char>,
200 : Alloc>& s)
201 : {
202 3 : return append_to_t<Alloc>(s);
203 : }
204 : #endif
205 :
206 : //------------------------------------------------
207 :
208 : /** A token for assigning to a plain string
209 : */
210 : #ifdef BOOST_URL_DOCS
211 : template<
212 : class Allocator =
213 : std::allocator<char>>
214 : __implementation_defined__
215 : assign_to(
216 : std::basic_string<
217 : char,
218 : std::char_traits<char>,
219 : Allocator>& s);
220 : #else
221 : template<class Alloc>
222 : struct assign_to_t
223 : : arg
224 : {
225 : using string_type = std::basic_string<
226 : char, std::char_traits<char>,
227 : Alloc>;
228 :
229 : using result_type = string_type&;
230 :
231 : explicit
232 337 : assign_to_t(
233 : string_type& s) noexcept
234 337 : : s_(s)
235 : {
236 337 : }
237 :
238 : char*
239 337 : prepare(std::size_t n) override
240 : {
241 337 : s_.resize(n);
242 337 : return &s_[0];
243 : }
244 :
245 : result_type
246 337 : result() noexcept
247 : {
248 337 : return s_;
249 : }
250 :
251 : private:
252 : string_type& s_;
253 : };
254 :
255 : template<
256 : class Alloc =
257 : std::allocator<char>>
258 : assign_to_t<Alloc>
259 337 : assign_to(
260 : std::basic_string<
261 : char,
262 : std::char_traits<char>,
263 : Alloc>& s)
264 : {
265 337 : return assign_to_t<Alloc>(s);
266 : }
267 : #endif
268 :
269 : //------------------------------------------------
270 :
271 : /** A token for producing a durable core::string_view from a temporary string
272 : */
273 : #ifdef BOOST_URL_DOCS
274 : template<
275 : class Allocator =
276 : std::allocator<char>>
277 : __implementation_defined__
278 : preserve_size(
279 : std::basic_string<
280 : char,
281 : std::char_traits<char>,
282 : Allocator>& s);
283 : #else
284 : template<class Alloc>
285 : struct preserve_size_t
286 : : arg
287 : {
288 : using result_type = core::string_view;
289 :
290 : using string_type = std::basic_string<
291 : char, std::char_traits<char>,
292 : Alloc>;
293 :
294 : explicit
295 4 : preserve_size_t(
296 : string_type& s) noexcept
297 4 : : s_(s)
298 : {
299 4 : }
300 :
301 : char*
302 4 : prepare(std::size_t n) override
303 : {
304 4 : n_ = n;
305 : // preserve size() to
306 : // avoid value-init
307 4 : if(s_.size() < n)
308 2 : s_.resize(n);
309 4 : return &s_[0];
310 : }
311 :
312 : result_type
313 4 : result() noexcept
314 : {
315 4 : return core::string_view(
316 8 : s_.data(), n_);
317 : }
318 :
319 : private:
320 : string_type& s_;
321 : std::size_t n_ = 0;
322 : };
323 :
324 : template<
325 : class Alloc =
326 : std::allocator<char>>
327 : preserve_size_t<Alloc>
328 4 : preserve_size(
329 : std::basic_string<
330 : char,
331 : std::char_traits<char>,
332 : Alloc>& s)
333 : {
334 4 : return preserve_size_t<Alloc>(s);
335 : }
336 : #endif
337 :
338 : } // string_token
339 :
340 : namespace grammar {
341 : namespace string_token = ::boost::urls::string_token;
342 : } // grammar
343 :
344 : } // urls
345 : } // boost
346 :
347 : #endif
|