pct_string_view.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. //
  2. // Copyright (c) 2022 Vinnie Falco ([email protected])
  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_PCT_STRING_VIEW_HPP
  10. #define BOOST_URL_PCT_STRING_VIEW_HPP
  11. #include <boost/url/detail/config.hpp>
  12. #include <boost/url/encoding_opts.hpp>
  13. #include <boost/url/error_types.hpp>
  14. #include <boost/core/detail/string_view.hpp>
  15. #include <boost/url/grammar/string_token.hpp>
  16. #include <boost/url/grammar/string_view_base.hpp>
  17. #include <cstddef>
  18. #include <iterator>
  19. #include <string>
  20. #include <type_traits>
  21. #include <utility>
  22. namespace boost {
  23. namespace urls {
  24. //------------------------------------------------
  25. #ifndef BOOST_URL_DOCS
  26. class decode_view;
  27. class pct_string_view;
  28. pct_string_view
  29. make_pct_string_view_unsafe(
  30. char const*, std::size_t,
  31. std::size_t) noexcept;
  32. namespace detail {
  33. core::string_view&
  34. ref(pct_string_view& s) noexcept;
  35. } // detail
  36. #endif
  37. //------------------------------------------------
  38. /** A reference to a valid percent-encoded string
  39. Objects of this type behave like a
  40. `core::string_view` and have the same interface,
  41. but offer an additional invariant: they can
  42. only be constructed from strings containing
  43. valid percent-escapes.
  44. Attempting construction from a string
  45. containing invalid or malformed percent
  46. escapes results in an exception.
  47. @par Operators
  48. The following operators are supported between
  49. @ref pct_string_view and any object that is
  50. convertible to `core::string_view`
  51. @code
  52. bool operator==( pct_string_view, pct_string_view ) noexcept;
  53. bool operator!=( pct_string_view, pct_string_view ) noexcept;
  54. bool operator<=( pct_string_view, pct_string_view ) noexcept;
  55. bool operator< ( pct_string_view, pct_string_view ) noexcept;
  56. bool operator> ( pct_string_view, pct_string_view ) noexcept;
  57. bool operator>=( pct_string_view, pct_string_view ) noexcept;
  58. @endcode
  59. */
  60. class pct_string_view final
  61. : public grammar::string_view_base
  62. {
  63. std::size_t dn_ = 0;
  64. #ifndef BOOST_URL_DOCS
  65. friend
  66. pct_string_view
  67. make_pct_string_view_unsafe(
  68. char const*, std::size_t,
  69. std::size_t) noexcept;
  70. friend
  71. core::string_view&
  72. detail::ref(pct_string_view&) noexcept;
  73. #endif
  74. // unsafe
  75. pct_string_view(
  76. char const* data,
  77. std::size_t size,
  78. std::size_t dn) noexcept
  79. : string_view_base(data, size)
  80. , dn_(dn)
  81. {
  82. }
  83. BOOST_URL_DECL
  84. void
  85. decode_impl(
  86. string_token::arg& dest,
  87. encoding_opts opt) const;
  88. public:
  89. /** Constructor
  90. Default constructed string are empty.
  91. @par Complexity
  92. Constant.
  93. @par Exception Safety
  94. Throws nothing.
  95. */
  96. constexpr pct_string_view() = default;
  97. /** Constructor
  98. The copy references the same
  99. underlying character buffer.
  100. Ownership is not transferred.
  101. @par Postconditions
  102. @code
  103. this->data() == other.data()
  104. @endcode
  105. @par Complexity
  106. Constant.
  107. @par Exception Safety
  108. Throws nothing.
  109. @par other The string to copy.
  110. */
  111. constexpr
  112. pct_string_view(
  113. pct_string_view const& other) = default;
  114. /** Constructor
  115. The newly constructed string references
  116. the specified character buffer.
  117. Ownership is not transferred.
  118. @par Postconditions
  119. @code
  120. this->data() == core::string_view(s).data()
  121. @endcode
  122. @par Complexity
  123. Linear in `core::string_view(s).size()`.
  124. @par Exception Safety
  125. Exceptions thrown on invalid input.
  126. @throw system_error
  127. The string contains an invalid percent encoding.
  128. @tparam String A type convertible to `core::string_view`
  129. @param s The string to construct from.
  130. */
  131. template<
  132. class String
  133. #ifndef BOOST_URL_DOCS
  134. , class = typename std::enable_if<
  135. std::is_convertible<
  136. String,
  137. core::string_view
  138. >::value>::type
  139. #endif
  140. >
  141. pct_string_view(
  142. String const& s)
  143. : pct_string_view(
  144. detail::to_sv(s))
  145. {
  146. }
  147. /** Constructor (deleted)
  148. */
  149. pct_string_view(
  150. std::nullptr_t) = delete;
  151. /** Constructor
  152. The newly constructed string references
  153. the specified character buffer. Ownership
  154. is not transferred.
  155. @par Postconditions
  156. @code
  157. this->data() == s && this->size() == len
  158. @endcode
  159. @par Complexity
  160. Linear in `len`.
  161. @par Exception Safety
  162. Exceptions thrown on invalid input.
  163. @throw system_error
  164. The string contains an invalid percent encoding.
  165. @param s, len The string to construct from.
  166. */
  167. pct_string_view(
  168. char const* s,
  169. std::size_t len)
  170. : pct_string_view(
  171. core::string_view(s, len))
  172. {
  173. }
  174. /** Constructor
  175. The newly constructed string references
  176. the specified character buffer. Ownership
  177. is not transferred.
  178. @par Postconditions
  179. @code
  180. this->data() == s.data() && this->size() == s.size()
  181. @endcode
  182. @par Complexity
  183. Linear in `s.size()`.
  184. @par Exception Safety
  185. Exceptions thrown on invalid input.
  186. @throw system_error
  187. The string contains an invalid percent encoding.
  188. @param s The string to construct from.
  189. */
  190. BOOST_URL_DECL
  191. pct_string_view(
  192. core::string_view s);
  193. /** Assignment
  194. The copy references the same
  195. underlying character buffer.
  196. Ownership is not transferred.
  197. @par Postconditions
  198. @code
  199. this->data() == other.data()
  200. @endcode
  201. @par Complexity
  202. Constant.
  203. @par Exception Safety
  204. Throws nothing.
  205. @par other The string to copy.
  206. */
  207. pct_string_view& operator=(
  208. pct_string_view const& other) = default;
  209. friend
  210. BOOST_URL_DECL
  211. system::result<pct_string_view>
  212. make_pct_string_view(
  213. core::string_view s) noexcept;
  214. //--------------------------------------------
  215. /** Return the decoded size
  216. This function returns the number of
  217. characters in the resulting string if
  218. percent escapes were converted into
  219. ordinary characters.
  220. @par Complexity
  221. Constant.
  222. @par Exception Safety
  223. Throws nothing.
  224. */
  225. std::size_t
  226. decoded_size() const noexcept
  227. {
  228. return dn_;
  229. }
  230. /** Return the string as a range of decoded characters
  231. @par Complexity
  232. Constant.
  233. @par Exception Safety
  234. Throws nothing.
  235. @see
  236. @ref decode_view.
  237. */
  238. decode_view
  239. operator*() const noexcept;
  240. /** Return the string with percent-decoding
  241. This function converts percent escapes
  242. in the string into ordinary characters
  243. and returns the result.
  244. When called with no arguments, the
  245. return type is `std::string`.
  246. Otherwise, the return type and style
  247. of output is determined by which string
  248. token is passed.
  249. @par Example
  250. @code
  251. assert( pct_string_view( "Program%20Files" ).decode() == "Program Files" );
  252. @endcode
  253. @par Complexity
  254. Linear in `this->size()`.
  255. @par Exception Safety
  256. Calls to allocate may throw.
  257. String tokens may throw exceptions.
  258. @param opt The options for encoding. If
  259. this parameter is omitted, the default
  260. options are used.
  261. @param token An optional string token.
  262. If this parameter is omitted, then
  263. a new `std::string` is returned.
  264. Otherwise, the function return type
  265. is the result type of the token.
  266. @see
  267. @ref encoding_opts,
  268. @ref string_token::return_string.
  269. */
  270. template<BOOST_URL_STRTOK_TPARAM>
  271. BOOST_URL_STRTOK_RETURN
  272. decode(
  273. encoding_opts opt = {},
  274. BOOST_URL_STRTOK_ARG(token)) const
  275. {
  276. /* If you get a compile error here, it
  277. means that the token you passed does
  278. not meet the requirements stated
  279. in the documentation.
  280. */
  281. static_assert(
  282. string_token::is_token<
  283. StringToken>::value,
  284. "Type requirements not met");
  285. decode_impl(token, opt);
  286. return token.result();
  287. }
  288. #ifndef BOOST_URL_DOCS
  289. // arrow support
  290. pct_string_view const*
  291. operator->() const noexcept
  292. {
  293. return this;
  294. }
  295. #endif
  296. //--------------------------------------------
  297. // VFALCO No idea why this fails in msvc
  298. /** Swap
  299. */
  300. /*BOOST_CXX14_CONSTEXPR*/ void swap(
  301. pct_string_view& s ) noexcept
  302. {
  303. string_view_base::swap(s);
  304. std::swap(dn_, s.dn_);
  305. }
  306. };
  307. //------------------------------------------------
  308. #ifndef BOOST_URL_DOCS
  309. namespace detail {
  310. // obtain modifiable reference to
  311. // underlying string, to handle
  312. // self-intersection on modifiers.
  313. inline
  314. core::string_view&
  315. ref(pct_string_view& s) noexcept
  316. {
  317. return s.s_;
  318. }
  319. } // detail
  320. #endif
  321. //------------------------------------------------
  322. /** Return a valid percent-encoded string
  323. If `s` is a valid percent-encoded string,
  324. the function returns the buffer as a valid
  325. view which may be used to perform decoding
  326. or measurements.
  327. Otherwise the result contains an error code.
  328. Upon success, the returned view references
  329. the original character buffer;
  330. Ownership is not transferred.
  331. @par Complexity
  332. Linear in `s.size()`.
  333. @par Exception Safety
  334. Throws nothing.
  335. @param s The string to validate.
  336. */
  337. BOOST_URL_DECL
  338. system::result<pct_string_view>
  339. make_pct_string_view(
  340. core::string_view s) noexcept;
  341. #ifndef BOOST_URL_DOCS
  342. // VFALCO semi-private for now
  343. inline
  344. pct_string_view
  345. make_pct_string_view_unsafe(
  346. char const* data,
  347. std::size_t size,
  348. std::size_t decoded_size) noexcept
  349. {
  350. #if 0
  351. BOOST_ASSERT(! make_pct_string_view(
  352. core::string_view(data, size)).has_error());
  353. #endif
  354. return pct_string_view(
  355. data, size, decoded_size);
  356. }
  357. #endif
  358. #ifndef BOOST_URL_DOCS
  359. namespace detail {
  360. template <>
  361. inline
  362. core::string_view
  363. to_sv(pct_string_view const& s) noexcept
  364. {
  365. return s.substr();
  366. }
  367. } // detail
  368. #endif
  369. } // urls
  370. } // boost
  371. #endif