params_ref.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  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_REF_HPP
  11. #define BOOST_URL_PARAMS_REF_HPP
  12. #include <boost/url/detail/config.hpp>
  13. #include <boost/url/ignore_case.hpp>
  14. #include <boost/url/params_base.hpp>
  15. #include <initializer_list>
  16. #include <iterator>
  17. namespace boost {
  18. namespace urls {
  19. #ifndef BOOST_URL_DOCS
  20. class url_base;
  21. class params_view;
  22. #endif
  23. /** A view representing query parameters in a URL
  24. Objects of this type are used to interpret
  25. the query parameters as a bidirectional view
  26. of key/value pairs.
  27. The view does not retain ownership of the
  28. elements and instead references the original
  29. url. The caller is responsible for ensuring
  30. that the lifetime of the referenced url
  31. extends until it is no longer referenced.
  32. The view is modifiable; calling non-const
  33. members causes changes to the referenced
  34. url.
  35. <br>
  36. Percent escapes in strings returned when
  37. dereferencing iterators are automatically
  38. decoded.
  39. Reserved characters in strings supplied
  40. to modifier functions are automatically
  41. percent-escaped.
  42. @par Example
  43. @code
  44. url u( "?first=John&last=Doe" );
  45. params_ref p = u.params();
  46. @endcode
  47. @par Iterator Invalidation
  48. Changes to the underlying character buffer
  49. can invalidate iterators which reference it.
  50. Modifications made through the container
  51. invalidate some or all iterators:
  52. <br>
  53. @li @ref append : Only `end()`.
  54. @li @ref assign, @ref clear,
  55. `operator=` : All elements.
  56. @li @ref erase : Erased elements and all
  57. elements after (including `end()`).
  58. @li @ref insert : All elements at or after
  59. the insertion point (including `end()`).
  60. @li @ref replace, @ref set : Modified
  61. elements and all elements
  62. after (including `end()`).
  63. */
  64. class params_ref
  65. : public params_base
  66. {
  67. friend class url_base;
  68. url_base* u_ = nullptr;
  69. params_ref(
  70. url_base& u,
  71. encoding_opts opt) noexcept;
  72. public:
  73. //--------------------------------------------
  74. //
  75. // Special Members
  76. //
  77. //--------------------------------------------
  78. /** Constructor
  79. After construction, both views
  80. reference the same url. Ownership is not
  81. transferred; the caller is responsible
  82. for ensuring the lifetime of the url
  83. extends until it is no longer
  84. referenced.
  85. @par Postconditions
  86. @code
  87. &this->url() == &other.url()
  88. @endcode
  89. @par Complexity
  90. Constant.
  91. @par Exception Safety
  92. Throws nothing.
  93. @param other The other view.
  94. */
  95. params_ref(
  96. params_ref const& other) = default;
  97. /** Constructor
  98. After construction, both views will
  99. reference the same url but this
  100. instance will use the specified
  101. @ref encoding_opts when the values
  102. are decoded.
  103. Ownership is not transferred; the
  104. caller is responsible for ensuring
  105. the lifetime of the url extends
  106. until it is no longer referenced.
  107. @par Postconditions
  108. @code
  109. &this->url() == &other.url()
  110. @endcode
  111. @par Complexity
  112. Constant.
  113. @par Exception Safety
  114. Throws nothing.
  115. @param other The other view.
  116. @param opt The options for decoding. If
  117. this parameter is omitted, `space_as_plus`
  118. is used.
  119. */
  120. params_ref(
  121. params_ref const& other,
  122. encoding_opts opt) noexcept;
  123. /** Assignment
  124. The previous contents of this are
  125. replaced by the contents of `other.
  126. <br>
  127. All iterators are invalidated.
  128. @note
  129. The strings referenced by `other`
  130. must not come from the underlying url,
  131. or else the behavior is undefined.
  132. @par Effects
  133. @code
  134. this->assign( other.begin(), other.end() );
  135. @endcode
  136. @par Complexity
  137. Linear in `other.buffer().size()`.
  138. @par Exception Safety
  139. Strong guarantee.
  140. Calls to allocate may throw.
  141. @param other The params to assign.
  142. */
  143. BOOST_URL_DECL
  144. params_ref&
  145. operator=(
  146. params_ref const& other);
  147. /** Assignment
  148. After assignment, the previous contents
  149. of the query parameters are replaced by
  150. the contents of the initializer-list.
  151. @par Preconditions
  152. None of character buffers referenced by
  153. `init` may overlap the character buffer of
  154. the underlying url, or else the behavior
  155. is undefined.
  156. @par Effects
  157. @code
  158. this->assign( init );
  159. @endcode
  160. @par Complexity
  161. Linear in `init.size()`.
  162. @par Exception Safety
  163. Strong guarantee.
  164. Calls to allocate may throw.
  165. @param init The list of params to assign.
  166. */
  167. params_ref&
  168. operator=(
  169. std::initializer_list<
  170. param_view> init);
  171. /** Conversion
  172. */
  173. BOOST_URL_DECL
  174. operator
  175. params_view() const noexcept;
  176. //--------------------------------------------
  177. //
  178. // Observers
  179. //
  180. //--------------------------------------------
  181. /** Return the referenced url
  182. This function returns the url referenced
  183. by the view.
  184. @par Example
  185. @code
  186. url u( "?key=value" );
  187. assert( &u.segments().url() == &u );
  188. @endcode
  189. @par Exception Safety
  190. @code
  191. Throws nothing.
  192. @endcode
  193. */
  194. url_base&
  195. url() const noexcept
  196. {
  197. return *u_;
  198. }
  199. //--------------------------------------------
  200. //
  201. // Modifiers
  202. //
  203. //--------------------------------------------
  204. /** Clear the contents of the container
  205. <br>
  206. All iterators are invalidated.
  207. @par Effects
  208. @code
  209. this->url().remove_query();
  210. @endcode
  211. @par Postconditions
  212. @code
  213. this->empty() == true && this->url().has_query() == false
  214. @endcode
  215. @par Complexity
  216. Constant.
  217. @par Exception Safety
  218. Throws nothing.
  219. */
  220. void
  221. clear() noexcept;
  222. //--------------------------------------------
  223. /** Assign elements
  224. This function replaces the entire
  225. contents of the view with the params
  226. in the <em>initializer-list</em>.
  227. <br>
  228. All iterators are invalidated.
  229. @note
  230. The strings referenced by the inputs
  231. must not come from the underlying url,
  232. or else the behavior is undefined.
  233. @par Example
  234. @code
  235. url u;
  236. u.params().assign( {{ "first", "John" }, { "last", "Doe" }} );
  237. @endcode
  238. @par Complexity
  239. Linear in `init.size()`.
  240. @par Exception Safety
  241. Strong guarantee.
  242. Calls to allocate may throw.
  243. @param init The list of params to assign.
  244. */
  245. BOOST_URL_DECL
  246. void
  247. assign(
  248. std::initializer_list<
  249. param_view> init);
  250. /** Assign elements
  251. This function replaces the entire
  252. contents of the view with the params
  253. in the range.
  254. <br>
  255. All iterators are invalidated.
  256. @note
  257. The strings referenced by the inputs
  258. must not come from the underlying url,
  259. or else the behavior is undefined.
  260. @par Mandates
  261. @code
  262. std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
  263. @endcode
  264. @par Complexity
  265. Linear in the size of the range.
  266. @par Exception Safety
  267. Strong guarantee.
  268. Calls to allocate may throw.
  269. @param first, last The range of params
  270. to assign.
  271. */
  272. template<class FwdIt>
  273. void
  274. assign(FwdIt first, FwdIt last);
  275. //--------------------------------------------
  276. /** Append elements
  277. This function appends a param to the view.
  278. <br>
  279. The `end()` iterator is invalidated.
  280. @par Example
  281. @code
  282. url u;
  283. u.params().append( { "first", "John" } );
  284. @endcode
  285. @par Complexity
  286. Linear in `this->url().encoded_query().size()`.
  287. @par Exception Safety
  288. Strong guarantee.
  289. Calls to allocate may throw.
  290. @return An iterator to the new element.
  291. @param p The param to append.
  292. */
  293. iterator
  294. append(
  295. param_view const& p);
  296. /** Append elements
  297. This function appends the params in
  298. an <em>initializer-list</em> to the view.
  299. <br>
  300. The `end()` iterator is invalidated.
  301. @par Example
  302. @code
  303. url u;
  304. u.params().append({ { "first", "John" }, { "last", "Doe" } });
  305. @endcode
  306. @par Complexity
  307. Linear in `this->url().encoded_query().size()`.
  308. @par Exception Safety
  309. Strong guarantee.
  310. Calls to allocate may throw.
  311. @return An iterator to the first new element.
  312. @param init The list of params to append.
  313. */
  314. iterator
  315. append(
  316. std::initializer_list<
  317. param_view> init);
  318. /** Append elements
  319. This function appends a range of params
  320. to the view.
  321. <br>
  322. The `end()` iterator is invalidated.
  323. @note
  324. The strings referenced by the inputs
  325. must not come from the underlying url,
  326. or else the behavior is undefined.
  327. @par Mandates
  328. @code
  329. std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
  330. @endcode
  331. @par Complexity
  332. Linear in `this->url().encoded_query().size()`.
  333. @par Exception Safety
  334. Strong guarantee.
  335. Calls to allocate may throw.
  336. @return An iterator to the first new element.
  337. @param first, last The range of params
  338. to append.
  339. */
  340. template<class FwdIt>
  341. iterator
  342. append(
  343. FwdIt first, FwdIt last);
  344. //--------------------------------------------
  345. /** Insert elements
  346. This function inserts a param
  347. before the specified position.
  348. <br>
  349. All iterators that are equal to
  350. `before` or come after are invalidated.
  351. @par Complexity
  352. Linear in `this->url().encoded_query().size()`.
  353. @par Exception Safety
  354. Strong guarantee.
  355. Calls to allocate may throw.
  356. @return An iterator to the inserted
  357. element.
  358. @param before An iterator before which
  359. the param is inserted. This may
  360. be equal to `end()`.
  361. @param p The param to insert.
  362. */
  363. BOOST_URL_DECL
  364. iterator
  365. insert(
  366. iterator before,
  367. param_view const& p);
  368. /** Insert elements
  369. This function inserts the params in
  370. an <em>initializer-list</em> before
  371. the specified position.
  372. <br>
  373. All iterators that are equal to
  374. `before` or come after are invalidated.
  375. @note
  376. The strings referenced by the inputs
  377. must not come from the underlying url,
  378. or else the behavior is undefined.
  379. @par Complexity
  380. Linear in `this->url().encoded_query().size()`.
  381. @par Exception Safety
  382. Strong guarantee.
  383. Calls to allocate may throw.
  384. @return An iterator to the first
  385. element inserted, or `before` if
  386. `init.size() == 0`.
  387. @param before An iterator before which
  388. the element is inserted. This may
  389. be equal to `end()`.
  390. @param init The list of params to insert.
  391. */
  392. BOOST_URL_DECL
  393. iterator
  394. insert(
  395. iterator before,
  396. std::initializer_list<
  397. param_view> init);
  398. /** Insert elements
  399. This function inserts a range of
  400. params before the specified position.
  401. <br>
  402. All iterators that are equal to
  403. `before` or come after are invalidated.
  404. @note
  405. The strings referenced by the inputs
  406. must not come from the underlying url,
  407. or else the behavior is undefined.
  408. @par Mandates
  409. @code
  410. std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
  411. @endcode
  412. @par Complexity
  413. Linear in `this->url().encoded_query().size()`.
  414. @par Exception Safety
  415. Strong guarantee.
  416. Calls to allocate may throw.
  417. @return An iterator to the first
  418. element inserted, or `before` if
  419. `first == last`.
  420. @param before An iterator before which
  421. the element is inserted. This may
  422. be equal to `end()`.
  423. @param first, last The range of params
  424. to insert.
  425. */
  426. template<class FwdIt>
  427. iterator
  428. insert(
  429. iterator before,
  430. FwdIt first,
  431. FwdIt last);
  432. //--------------------------------------------
  433. /** Erase elements
  434. This function removes an element from
  435. the container.
  436. <br>
  437. All iterators that are equal to
  438. `pos` or come after are invalidated.
  439. @par Example
  440. @code
  441. url u( "?first=John&last=Doe" );
  442. params_ref::iterator it = u.params().erase( u.params().begin() );
  443. assert( u.encoded_query() == "last=Doe" );
  444. @endcode
  445. @par Complexity
  446. Linear in `this->url().encoded_query().size()`.
  447. @par Exception Safety
  448. Throws nothing.
  449. @return An iterator to one past
  450. the removed element.
  451. @param pos An iterator to the element.
  452. */
  453. iterator
  454. erase(iterator pos) noexcept;
  455. /** Erase elements
  456. This function removes a range of elements
  457. from the container.
  458. <br>
  459. All iterators that are equal to
  460. `first` or come after are invalidated.
  461. @par Complexity
  462. Linear in `this->url().encoded_query().size()`.
  463. @par Exception Safety
  464. Throws nothing.
  465. @return An iterator to one past
  466. the removed range.
  467. @param first, last The range of
  468. elements to erase.
  469. */
  470. iterator
  471. erase(
  472. iterator first,
  473. iterator last) noexcept;
  474. /** Erase elements
  475. <br>
  476. All iterators are invalidated.
  477. @par Postconditions
  478. @code
  479. this->count( key, ic ) == 0
  480. @endcode
  481. @par Complexity
  482. Linear in `this->url().encoded_query().size()`.
  483. @par Exception Safety
  484. Throws nothing.
  485. @return The number of elements removed
  486. from the container.
  487. @param key The key to match.
  488. By default, a case-sensitive
  489. comparison is used.
  490. @param ic An optional parameter. If
  491. the value @ref ignore_case is passed
  492. here, the comparison is
  493. case-insensitive.
  494. */
  495. BOOST_URL_DECL
  496. std::size_t
  497. erase(
  498. string_view key,
  499. ignore_case_param ic = {}) noexcept;
  500. //--------------------------------------------
  501. /** Replace elements
  502. This function replaces the contents
  503. of the element at `pos` with the
  504. specified param.
  505. <br>
  506. All iterators that are equal to
  507. `pos` or come after are invalidated.
  508. @par Example
  509. @code
  510. url u( "?first=John&last=Doe" );
  511. u.params().replace( u.params().begin(), { "title", "Mr" });
  512. assert( u.encoded_query() == "title=Mr&last=Doe" );
  513. @endcode
  514. @par Complexity
  515. Linear in `this->url().encoded_query().size()`.
  516. @par Exception Safety
  517. Strong guarantee.
  518. Calls to allocate may throw.
  519. @return An iterator to the element.
  520. @param pos An iterator to the element.
  521. @param p The param to assign.
  522. */
  523. BOOST_URL_DECL
  524. iterator
  525. replace(
  526. iterator pos,
  527. param_view const& p);
  528. /** Replace elements
  529. This function replaces a range of
  530. elements with the params in an
  531. <em>initializer-list</em>.
  532. <br>
  533. All iterators that are equal to
  534. `from` or come after are invalidated.
  535. @note
  536. The strings referenced by the inputs
  537. must not come from the underlying url,
  538. or else the behavior is undefined.
  539. @par Complexity
  540. Linear in `this->url().encoded_query().size()`.
  541. @par Exception Safety
  542. Strong guarantee.
  543. Calls to allocate may throw.
  544. @return An iterator to the first
  545. element inserted, or one past `to` if
  546. `init.size() == 0`.
  547. @param from,to The range of elements
  548. to replace.
  549. @param init The list of params to assign.
  550. */
  551. BOOST_URL_DECL
  552. iterator
  553. replace(
  554. iterator from,
  555. iterator to,
  556. std::initializer_list<
  557. param_view> init);
  558. /** Replace elements
  559. This function replaces a range of
  560. elements with a range of params.
  561. <br>
  562. All iterators that are equal to
  563. `from` or come after are invalidated.
  564. @note
  565. The strings referenced by the inputs
  566. must not come from the underlying url,
  567. or else the behavior is undefined.
  568. @par Mandates
  569. @code
  570. std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
  571. @endcode
  572. @par Complexity
  573. Linear in `this->url().encoded_query().size()`.
  574. @par Exception Safety
  575. Strong guarantee.
  576. Calls to allocate may throw.
  577. @return An iterator to the first
  578. element inserted, or one past `to` if
  579. `first == last`.
  580. @param from,to The range of elements to
  581. replace.
  582. @param first, last The range of params
  583. to assign.
  584. */
  585. template<class FwdIt>
  586. iterator
  587. replace(
  588. iterator from,
  589. iterator to,
  590. FwdIt first,
  591. FwdIt last);
  592. //--------------------------------------------
  593. /** Remove the value on an element
  594. This function removes the value of
  595. an element at the specified position.
  596. After the call returns, `has_value`
  597. for the element is false.
  598. <br>
  599. All iterators that are equal to
  600. `pos` or come after are invalidated.
  601. @par Example
  602. @code
  603. url u( "?first=John&last=Doe" );
  604. u.params().unset( u.params().begin() );
  605. assert( u.encoded_query() == "first&last=Doe" );
  606. @endcode
  607. @par Complexity
  608. Linear in `this->url().encoded_query().size()`.
  609. @par Exception Safety
  610. Throws nothing.
  611. @return An iterator to the element.
  612. @param pos An iterator to the element.
  613. */
  614. BOOST_URL_DECL
  615. iterator
  616. unset(
  617. iterator pos) noexcept;
  618. /** Set a value
  619. This function replaces the value of an
  620. element at the specified position.
  621. <br>
  622. All iterators that are equal to
  623. `pos` or come after are invalidated.
  624. @par Example
  625. @code
  626. url u( "?id=42&id=69" );
  627. u.params().set( u.params().begin(), "none" );
  628. assert( u.encoded_query() == "id=none&id=69" );
  629. @endcode
  630. @par Complexity
  631. Linear in `this->url().encoded_query().size()`.
  632. @par Exception Safety
  633. Strong guarantee.
  634. Calls to allocate may throw.
  635. @return An iterator to the element.
  636. @param pos An iterator to the element.
  637. @param value The value to assign. The
  638. empty string still counts as a value.
  639. That is, `has_value` for the element
  640. is true.
  641. */
  642. BOOST_URL_DECL
  643. iterator
  644. set(
  645. iterator pos,
  646. string_view value);
  647. /** Set a value
  648. This function performs one of two
  649. actions depending on the value of
  650. `this->contains( key, ic )`.
  651. @li If key is contained in the view
  652. then one of the matching elements has
  653. its value changed to the specified value.
  654. The remaining elements with a matching
  655. key are erased. Otherwise,
  656. @li If `key` is not contained in the
  657. view, then the function apppends the
  658. param `{ key, value }`.
  659. <br>
  660. All iterators are invalidated.
  661. @par Example
  662. @code
  663. url u( "?id=42&id=69" );
  664. u.params().set( "id", "none" );
  665. assert( u.params().count( "id" ) == 1 );
  666. @endcode
  667. @par Postconditions
  668. @code
  669. this->count( key, ic ) == 1 && this->find( key, ic )->value == value
  670. @endcode
  671. @par Complexity
  672. Linear in `this->url().encoded_query().size()`.
  673. @par Exception Safety
  674. Strong guarantee.
  675. Calls to allocate may throw.
  676. @return An iterator to the appended
  677. or modified element.
  678. @param key The key to match.
  679. By default, a case-sensitive
  680. comparison is used.
  681. @param value The value to assign. The
  682. empty string still counts as a value.
  683. That is, `has_value` for the element
  684. is true.
  685. @param ic An optional parameter. If
  686. the value @ref ignore_case is passed
  687. here, the comparison is
  688. case-insensitive.
  689. */
  690. BOOST_URL_DECL
  691. iterator
  692. set(
  693. string_view key,
  694. string_view value,
  695. ignore_case_param ic = {});
  696. //--------------------------------------------
  697. private:
  698. BOOST_URL_DECL
  699. detail::params_iter_impl
  700. find_impl(
  701. detail::params_iter_impl,
  702. string_view,
  703. ignore_case_param) const noexcept;
  704. BOOST_URL_DECL
  705. detail::params_iter_impl
  706. find_last_impl(
  707. detail::params_iter_impl,
  708. string_view,
  709. ignore_case_param) const noexcept;
  710. template<class FwdIt>
  711. void
  712. assign(FwdIt first, FwdIt last,
  713. std::forward_iterator_tag);
  714. // Doxygen cannot render ` = delete`
  715. template<class FwdIt>
  716. void
  717. assign(FwdIt first, FwdIt last,
  718. std::input_iterator_tag) = delete;
  719. template<class FwdIt>
  720. iterator
  721. insert(
  722. iterator before,
  723. FwdIt first,
  724. FwdIt last,
  725. std::forward_iterator_tag);
  726. // Doxygen cannot render ` = delete`
  727. template<class FwdIt>
  728. iterator
  729. insert(
  730. iterator before,
  731. FwdIt first,
  732. FwdIt last,
  733. std::input_iterator_tag) = delete;
  734. };
  735. } // urls
  736. } // boost
  737. // This is in <boost/url/url_base.hpp>
  738. //
  739. // #include <boost/url/impl/params_ref.hpp>
  740. #endif