params_base.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // Official repository: https://github.com/boostorg/url
  9. //
  10. #ifndef BOOST_URL_PARAMS_BASE_HPP
  11. #define BOOST_URL_PARAMS_BASE_HPP
  12. #include <boost/url/detail/config.hpp>
  13. #include <boost/url/encoding_opts.hpp>
  14. #include <boost/url/ignore_case.hpp>
  15. #include <boost/url/param.hpp>
  16. #include <boost/url/detail/params_iter_impl.hpp>
  17. #include <boost/url/detail/url_impl.hpp>
  18. #include <iosfwd>
  19. namespace boost {
  20. namespace urls {
  21. #ifdef BOOST_MSVC
  22. # pragma warning(push)
  23. // "struct 'boost::urls::encoding_opts' needs to have dll-interface to be used by clients of class 'boost::urls::params_base'"
  24. // but encoding_opts should not be BOOST_URL_DECL and params_base should be BOOST_URL_DECL.
  25. # pragma warning(disable: 4251)
  26. #endif
  27. /** Common functionality for query parameter containers
  28. The library uses this base class
  29. to provide common member functions for
  30. containers of query parameters.
  31. This class should not be instantiated
  32. directly; Instead, use one of the
  33. containers or functions:
  34. @par Containers
  35. @li @ref params_ref
  36. @li @ref params_view
  37. @li @ref params_encoded_ref
  38. @li @ref params_encoded_view
  39. */
  40. class BOOST_URL_DECL params_base
  41. {
  42. friend class url_view_base;
  43. friend class params_ref;
  44. friend class params_view;
  45. detail::query_ref ref_;
  46. encoding_opts opt_;
  47. params_base() noexcept;
  48. params_base(
  49. detail::query_ref const& ref,
  50. encoding_opts opt) noexcept;
  51. params_base(
  52. params_base const&) = default;
  53. params_base& operator=(
  54. params_base const&) = default;
  55. public:
  56. /** A Bidirectional iterator to a query parameter
  57. Objects of this type allow iteration
  58. through the parameters in the query.
  59. Any percent-escapes in returned strings
  60. are decoded first.
  61. The values returned are read-only;
  62. changes to parameters must be made
  63. through the container instead, if the
  64. container supports modification.
  65. <br>
  66. The strings produced when iterators are
  67. dereferenced belong to the iterator and
  68. become invalidated when that particular
  69. iterator is incremented, decremented,
  70. or destroyed.
  71. @note
  72. The implementation may use temporary,
  73. recycled storage to store decoded
  74. strings. These iterators are meant
  75. to be used ephemerally. That is, for
  76. short durations such as within a
  77. function scope. Do not store
  78. iterators with static storage
  79. duration or as long-lived objects.
  80. */
  81. class iterator;
  82. /// @copydoc iterator
  83. using const_iterator = iterator;
  84. /** The value type
  85. Values of this type represent parameters
  86. whose strings retain unique ownership by
  87. making a copy.
  88. @par Example
  89. @code
  90. params_view::value_type qp( *url_view( "?first=John&last=Doe" ).params().find( "first" ) );
  91. @endcode
  92. @see
  93. @ref param.
  94. */
  95. using value_type = param;
  96. /** The reference type
  97. This is the type of value returned when
  98. iterators of the view are dereferenced.
  99. @see
  100. @ref param_view.
  101. */
  102. using reference = param;
  103. /// @copydoc reference
  104. using const_reference = param;
  105. /** An unsigned integer type to represent sizes.
  106. */
  107. using size_type = std::size_t;
  108. /** A signed integer type used to represent differences.
  109. */
  110. using difference_type = std::ptrdiff_t;
  111. //--------------------------------------------
  112. //
  113. // Observers
  114. //
  115. //--------------------------------------------
  116. /** Return the maximum number of characters possible
  117. This represents the largest number of
  118. characters that are possible in a path,
  119. not including any null terminator.
  120. @par Exception Safety
  121. Throws nothing.
  122. @return The maximum number of characters possible.
  123. */
  124. static
  125. constexpr
  126. std::size_t
  127. max_size() noexcept
  128. {
  129. return BOOST_URL_MAX_SIZE;
  130. }
  131. /** Return the referenced character buffer.
  132. This function returns the character
  133. buffer referenced by the view.
  134. The returned string may contain
  135. percent escapes.
  136. @par Example
  137. @code
  138. assert( url_view( "?first=John&last=Doe" ).params().buffer() == "?first=John&last=Doe" );
  139. @endcode
  140. @par Complexity
  141. Constant.
  142. @par Exception Safety
  143. Throws nothing.
  144. @return The buffer.
  145. */
  146. pct_string_view
  147. buffer() const noexcept;
  148. /** Return true if there are no params
  149. @par Example
  150. @code
  151. assert( ! url_view( "?key=value" ).params().empty() );
  152. @endcode
  153. @par Complexity
  154. Constant.
  155. @par Exception Safety
  156. Throws nothing.
  157. @return `true` if there are no params.
  158. */
  159. bool
  160. empty() const noexcept;
  161. /** Return the number of params
  162. @par Example
  163. @code
  164. assert( url_view( "?key=value").params().size() == 1 );
  165. @endcode
  166. @par Complexity
  167. Constant.
  168. @par Exception Safety
  169. Throws nothing.
  170. @return The number of params.
  171. */
  172. std::size_t
  173. size() const noexcept;
  174. /** Return an iterator to the beginning
  175. @par Complexity
  176. Linear in the size of the first param.
  177. @par Exception Safety
  178. Throws nothing.
  179. @return An iterator to the beginning.
  180. */
  181. iterator
  182. begin() const noexcept;
  183. /** Return an iterator to the end
  184. @par Complexity
  185. Constant.
  186. @par Exception Safety
  187. Throws nothing.
  188. @return An iterator to the end.
  189. */
  190. iterator
  191. end() const noexcept;
  192. //--------------------------------------------
  193. /** Return true if a matching key exists
  194. This function examines the parameters
  195. in the container to find a match for
  196. the specified key.
  197. The comparison is performed as if all
  198. escaped characters were decoded first.
  199. @par Example
  200. @code
  201. assert( url_view( "?first=John&last=Doe" ).params().contains( "first" ) );
  202. @endcode
  203. @par Complexity
  204. Linear in `this->buffer().size()`.
  205. @par Exception Safety
  206. Throws nothing.
  207. @param key The key to match.
  208. By default, a case-sensitive
  209. comparison is used.
  210. @param ic An optional parameter. If
  211. the value @ref ignore_case is passed
  212. here, the comparison is
  213. case-insensitive.
  214. @return `true` if a matching key exists.
  215. */
  216. bool
  217. contains(
  218. core::string_view key,
  219. ignore_case_param ic = {}) const noexcept;
  220. /** Return the number of matching keys
  221. This function examines the
  222. parameters in the container to
  223. find the number of matches for
  224. the specified key.
  225. The comparison is performed as if all
  226. escaped characters were decoded first.
  227. @par Example
  228. @code
  229. assert( url_view( "?first=John&last=Doe" ).params().count( "first" ) == 1 );
  230. @endcode
  231. @par Complexity
  232. Linear in `this->buffer().size()`.
  233. @par Exception Safety
  234. Throws nothing.
  235. @param key The key to match.
  236. By default, a case-sensitive
  237. comparison is used.
  238. @param ic An optional parameter. If
  239. the value @ref ignore_case is passed
  240. here, the comparison is
  241. case-insensitive.
  242. @return The number of matching keys.
  243. */
  244. std::size_t
  245. count(
  246. core::string_view key,
  247. ignore_case_param ic = {}) const noexcept;
  248. /** Find a matching key
  249. This function examines the parameters
  250. in the container to find a match for
  251. the specified key.
  252. The comparison is performed as if all
  253. escaped characters were decoded first.
  254. <br>
  255. The search starts from the first param
  256. and proceeds forward until either the
  257. key is found or the end of the range is
  258. reached, in which case `end()` is
  259. returned.
  260. @par Example
  261. @code
  262. assert( (*url_view( "?first=John&last=Doe" ).params().find( "First", ignore_case )).value == "John" );
  263. @endcode
  264. @par Effects
  265. @code
  266. return this->find( this->begin(), key, ic );
  267. @endcode
  268. @par Complexity
  269. Linear in `this->buffer().size()`.
  270. @return an iterator to the param
  271. @param key The key to match.
  272. By default, a case-sensitive
  273. comparison is used.
  274. @param ic An optional parameter. If
  275. the value @ref ignore_case is passed
  276. here, the comparison is
  277. case-insensitive.
  278. */
  279. iterator
  280. find(
  281. core::string_view key,
  282. ignore_case_param ic = {}) const noexcept;
  283. /** Find a matching key
  284. This function examines the
  285. parameters in the container to
  286. find a match for the specified key.
  287. The comparison is performed as if all
  288. escaped characters were decoded first.
  289. <br>
  290. The search starts at `from`
  291. and proceeds forward until either the
  292. key is found or the end of the range is
  293. reached, in which case `end()` is
  294. returned.
  295. @par Example
  296. @code
  297. url_view u( "?First=John&Last=Doe" );
  298. assert( u.params().find( "first" ) != u.params().find( "first", ignore_case ) );
  299. @endcode
  300. @par Complexity
  301. Linear in `this->buffer().size()`.
  302. @return an iterator to the param
  303. @param from The position to begin the
  304. search from. This can be `end()`.
  305. @param key The key to match.
  306. By default, a case-sensitive
  307. comparison is used.
  308. @param ic An optional parameter. If
  309. the value @ref ignore_case is passed
  310. here, the comparison is
  311. case-insensitive.
  312. */
  313. iterator
  314. find(
  315. iterator from,
  316. core::string_view key,
  317. ignore_case_param ic = {}) const noexcept;
  318. /** Find a matching key
  319. This function examines the
  320. parameters in the container to
  321. find a match for the specified key.
  322. The comparison is performed as if all
  323. escaped characters were decoded first.
  324. <br>
  325. The search starts from the last param
  326. and proceeds backwards until either the
  327. key is found or the beginning of the
  328. range is reached, in which case `end()`
  329. is returned.
  330. @par Example
  331. @code
  332. assert( (*url_view( "?first=John&last=Doe" ).params().find_last( "last" )).value == "Doe" );
  333. @endcode
  334. @par Complexity
  335. Linear in `this->buffer().size()`.
  336. @return an iterator to the param
  337. @param key The key to match.
  338. By default, a case-sensitive
  339. comparison is used.
  340. @param ic An optional parameter. If
  341. the value @ref ignore_case is passed
  342. here, the comparison is
  343. case-insensitive.
  344. */
  345. iterator
  346. find_last(
  347. core::string_view key,
  348. ignore_case_param ic = {}) const noexcept;
  349. /** Find a matching key
  350. This function examines the
  351. parameters in the container to
  352. find a match for the specified key.
  353. The comparison is performed as if all
  354. escaped characters were decoded first.
  355. <br>
  356. The search starts prior to `before`
  357. and proceeds backwards until either the
  358. key is found or the beginning of the
  359. range is reached, in which case `end()`
  360. is returned.
  361. @par Example
  362. @code
  363. url_view u( "?First=John&Last=Doe" );
  364. assert( u.params().find_last( "last" ) != u.params().find_last( "last", ignore_case ) );
  365. @endcode
  366. @par Complexity
  367. Linear in `this->buffer().size()`.
  368. @return an iterator to the param
  369. @param before One past the position
  370. to begin the search from. This can
  371. be `end()`.
  372. @param key The key to match.
  373. By default, a case-sensitive
  374. comparison is used.
  375. @param ic An optional parameter. If
  376. the value @ref ignore_case is passed
  377. here, the comparison is
  378. case-insensitive.
  379. */
  380. iterator
  381. find_last(
  382. iterator before,
  383. core::string_view key,
  384. ignore_case_param ic = {}) const noexcept;
  385. private:
  386. detail::params_iter_impl
  387. find_impl(
  388. detail::params_iter_impl,
  389. core::string_view,
  390. ignore_case_param) const noexcept;
  391. detail::params_iter_impl
  392. find_last_impl(
  393. detail::params_iter_impl,
  394. core::string_view,
  395. ignore_case_param) const noexcept;
  396. };
  397. //------------------------------------------------
  398. /** Format to an output stream
  399. Any percent-escapes are emitted as-is;
  400. no decoding is performed.
  401. @par Complexity
  402. Linear in `ps.buffer().size()`.
  403. @par Effects
  404. @code
  405. return os << ps.buffer();
  406. @endcode
  407. @param os The output stream to write to
  408. @param qp The parameters to write
  409. @return A reference to the output stream, for chaining
  410. */
  411. BOOST_URL_DECL
  412. std::ostream&
  413. operator<<(
  414. std::ostream& os,
  415. params_base const& qp);
  416. } // urls
  417. } // boost
  418. #include <boost/url/impl/params_base.hpp>
  419. #ifdef BOOST_MSVC
  420. # pragma warning(pop)
  421. #endif
  422. #endif