string_token.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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. As the author of an
  24. algorithm simply declare an rvalue
  25. reference as a parameter type.
  26. <br>
  27. Instances of this type are intended only
  28. to be used once and then destroyed.
  29. @par Example
  30. The declared function accepts any
  31. temporary instance of `arg` to be
  32. used for writing:
  33. @code
  34. void algorithm( string_token::arg&& dest );
  35. @endcode
  36. To implement the interface for your type
  37. or use-case, derive from the class and
  38. implement the prepare function.
  39. */
  40. struct arg
  41. {
  42. /** Return a modifiable character buffer
  43. This function attempts to obtain a
  44. character buffer with space for at
  45. least `n` characters. Upon success,
  46. a pointer to the beginning of the
  47. buffer is returned. Ownership is not
  48. transferred; the caller should not
  49. attempt to free the storage. The
  50. buffer shall remain valid until
  51. `this` is destroyed.
  52. @note
  53. This function may only be called once.
  54. After invoking the function, the only
  55. valid operation is destruction.
  56. */
  57. virtual char* prepare(std::size_t n) = 0;
  58. // prevent misuse
  59. virtual ~arg() = default;
  60. arg() = default;
  61. arg(arg&&) = default;
  62. arg(arg const&) = delete;
  63. arg& operator=(arg&&) = delete;
  64. arg& operator=(arg const&) = delete;
  65. };
  66. //------------------------------------------------
  67. /** Metafunction returning true if T is a StringToken
  68. */
  69. #ifdef BOOST_URL_DOCS
  70. template<class T>
  71. using is_token = __see_below__;
  72. #else
  73. template<class T, class = void>
  74. struct is_token : std::false_type {};
  75. template<class T>
  76. struct is_token<T, void_t<
  77. decltype(std::declval<T&>().prepare(
  78. std::declval<std::size_t>())),
  79. decltype(std::declval<T&>().result())
  80. > > : std::integral_constant<bool,
  81. std::is_convertible<decltype(
  82. std::declval<T&>().result()),
  83. typename T::result_type>::value &&
  84. std::is_same<decltype(
  85. std::declval<T&>().prepare(0)),
  86. char*>::value &&
  87. std::is_base_of<arg, T>::value &&
  88. std::is_convertible<T const volatile*,
  89. arg const volatile*>::value
  90. >
  91. {
  92. };
  93. #endif
  94. //------------------------------------------------
  95. /** A token for returning a plain string
  96. */
  97. #ifdef BOOST_URL_DOCS
  98. using return_string = __implementation_defined__;
  99. #else
  100. struct return_string
  101. : arg
  102. {
  103. using result_type = std::string;
  104. char*
  105. prepare(std::size_t n) override
  106. {
  107. s_.resize(n);
  108. return &s_[0];
  109. }
  110. result_type
  111. result() noexcept
  112. {
  113. return std::move(s_);
  114. }
  115. private:
  116. result_type s_;
  117. };
  118. #endif
  119. //------------------------------------------------
  120. /** A token for appending to a plain string
  121. */
  122. #ifdef BOOST_URL_DOCS
  123. template<
  124. class Allocator =
  125. std::allocator<char>>
  126. __implementation_defined__
  127. append_to(
  128. std::basic_string<
  129. char,
  130. std::char_traits<char>,
  131. Allocator>& s);
  132. #else
  133. template<class Alloc>
  134. struct append_to_t
  135. : arg
  136. {
  137. using string_type = std::basic_string<
  138. char, std::char_traits<char>,
  139. Alloc>;
  140. using result_type = string_type&;
  141. explicit
  142. append_to_t(
  143. string_type& s) noexcept
  144. : s_(s)
  145. {
  146. }
  147. char*
  148. prepare(std::size_t n) override
  149. {
  150. std::size_t n0 = s_.size();
  151. if(n > s_.max_size() - n0)
  152. urls::detail::throw_length_error();
  153. s_.resize(n0 + n);
  154. return &s_[n0];
  155. }
  156. result_type
  157. result() noexcept
  158. {
  159. return s_;
  160. }
  161. private:
  162. string_type& s_;
  163. };
  164. template<
  165. class Alloc =
  166. std::allocator<char>>
  167. append_to_t<Alloc>
  168. append_to(
  169. std::basic_string<
  170. char,
  171. std::char_traits<char>,
  172. Alloc>& s)
  173. {
  174. return append_to_t<Alloc>(s);
  175. }
  176. #endif
  177. //------------------------------------------------
  178. /** A token for assigning to a plain string
  179. */
  180. #ifdef BOOST_URL_DOCS
  181. template<
  182. class Allocator =
  183. std::allocator<char>>
  184. __implementation_defined__
  185. assign_to(
  186. std::basic_string<
  187. char,
  188. std::char_traits<char>,
  189. Allocator>& s);
  190. #else
  191. template<class Alloc>
  192. struct assign_to_t
  193. : arg
  194. {
  195. using string_type = std::basic_string<
  196. char, std::char_traits<char>,
  197. Alloc>;
  198. using result_type = string_type&;
  199. explicit
  200. assign_to_t(
  201. string_type& s) noexcept
  202. : s_(s)
  203. {
  204. }
  205. char*
  206. prepare(std::size_t n) override
  207. {
  208. s_.resize(n);
  209. return &s_[0];
  210. }
  211. result_type
  212. result() noexcept
  213. {
  214. return s_;
  215. }
  216. private:
  217. string_type& s_;
  218. };
  219. template<
  220. class Alloc =
  221. std::allocator<char>>
  222. assign_to_t<Alloc>
  223. assign_to(
  224. std::basic_string<
  225. char,
  226. std::char_traits<char>,
  227. Alloc>& s)
  228. {
  229. return assign_to_t<Alloc>(s);
  230. }
  231. #endif
  232. //------------------------------------------------
  233. /** A token for producing a durable core::string_view from a temporary string
  234. */
  235. #ifdef BOOST_URL_DOCS
  236. template<
  237. class Allocator =
  238. std::allocator<char>>
  239. __implementation_defined__
  240. preserve_size(
  241. std::basic_string<
  242. char,
  243. std::char_traits<char>,
  244. Allocator>& s);
  245. #else
  246. template<class Alloc>
  247. struct preserve_size_t
  248. : arg
  249. {
  250. using result_type = core::string_view;
  251. using string_type = std::basic_string<
  252. char, std::char_traits<char>,
  253. Alloc>;
  254. explicit
  255. preserve_size_t(
  256. string_type& s) noexcept
  257. : s_(s)
  258. {
  259. }
  260. char*
  261. prepare(std::size_t n) override
  262. {
  263. n_ = n;
  264. // preserve size() to
  265. // avoid value-init
  266. if(s_.size() < n)
  267. s_.resize(n);
  268. return &s_[0];
  269. }
  270. result_type
  271. result() noexcept
  272. {
  273. return core::string_view(
  274. s_.data(), n_);
  275. }
  276. private:
  277. string_type& s_;
  278. std::size_t n_ = 0;
  279. };
  280. template<
  281. class Alloc =
  282. std::allocator<char>>
  283. preserve_size_t<Alloc>
  284. preserve_size(
  285. std::basic_string<
  286. char,
  287. std::char_traits<char>,
  288. Alloc>& s)
  289. {
  290. return preserve_size_t<Alloc>(s);
  291. }
  292. #endif
  293. } // string_token
  294. namespace grammar {
  295. namespace string_token = ::boost::urls::string_token;
  296. } // grammar
  297. } // urls
  298. } // boost
  299. #endif