string_token.hpp 11 KB

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