pct_string_view.hpp 10 KB

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