params_ref.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955
  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 BOOST_URL_DECL 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. params_ref&
  144. operator=(
  145. params_ref const& other);
  146. /** Assignment
  147. After assignment, the previous contents
  148. of the query parameters are replaced by
  149. the contents of the initializer-list.
  150. @par Preconditions
  151. None of character buffers referenced by
  152. `init` may overlap the character buffer of
  153. the underlying url, or else the behavior
  154. is undefined.
  155. @par Effects
  156. @code
  157. this->assign( init );
  158. @endcode
  159. @par Complexity
  160. Linear in `init.size()`.
  161. @par Exception Safety
  162. Strong guarantee.
  163. Calls to allocate may throw.
  164. @param init The list of params to assign.
  165. */
  166. params_ref&
  167. operator=(
  168. std::initializer_list<
  169. param_view> init);
  170. /** Conversion
  171. */
  172. operator
  173. params_view() const noexcept;
  174. //--------------------------------------------
  175. //
  176. // Observers
  177. //
  178. //--------------------------------------------
  179. /** Return the referenced url
  180. This function returns the url referenced
  181. by the view.
  182. @par Example
  183. @code
  184. url u( "?key=value" );
  185. assert( &u.segments().url() == &u );
  186. @endcode
  187. @par Exception Safety
  188. @code
  189. Throws nothing.
  190. @endcode
  191. */
  192. url_base&
  193. url() const noexcept
  194. {
  195. return *u_;
  196. }
  197. //--------------------------------------------
  198. //
  199. // Modifiers
  200. //
  201. //--------------------------------------------
  202. /** Clear the contents of the container
  203. <br>
  204. All iterators are invalidated.
  205. @par Effects
  206. @code
  207. this->url().remove_query();
  208. @endcode
  209. @par Postconditions
  210. @code
  211. this->empty() == true && this->url().has_query() == false
  212. @endcode
  213. @par Complexity
  214. Constant.
  215. @par Exception Safety
  216. Throws nothing.
  217. */
  218. void
  219. clear() noexcept;
  220. //--------------------------------------------
  221. /** Assign elements
  222. This function replaces the entire
  223. contents of the view with the params
  224. in the <em>initializer-list</em>.
  225. <br>
  226. All iterators are invalidated.
  227. @note
  228. The strings referenced by the inputs
  229. must not come from the underlying url,
  230. or else the behavior is undefined.
  231. @par Example
  232. @code
  233. url u;
  234. u.params().assign( {{ "first", "John" }, { "last", "Doe" }} );
  235. @endcode
  236. @par Complexity
  237. Linear in `init.size()`.
  238. @par Exception Safety
  239. Strong guarantee.
  240. Calls to allocate may throw.
  241. @param init The list of params to assign.
  242. */
  243. void
  244. assign(
  245. std::initializer_list<
  246. param_view> init);
  247. /** Assign elements
  248. This function replaces the entire
  249. contents of the view with the params
  250. in the range.
  251. <br>
  252. All iterators are invalidated.
  253. @note
  254. The strings referenced by the inputs
  255. must not come from the underlying url,
  256. or else the behavior is undefined.
  257. @par Mandates
  258. @code
  259. std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
  260. @endcode
  261. @par Complexity
  262. Linear in the size of the range.
  263. @par Exception Safety
  264. Strong guarantee.
  265. Calls to allocate may throw.
  266. @param first, last The range of params
  267. to assign.
  268. */
  269. template<class FwdIt>
  270. void
  271. assign(FwdIt first, FwdIt last);
  272. //--------------------------------------------
  273. /** Append elements
  274. This function appends a param to the view.
  275. <br>
  276. The `end()` iterator is invalidated.
  277. @par Example
  278. @code
  279. url u;
  280. u.params().append( { "first", "John" } );
  281. @endcode
  282. @par Complexity
  283. Linear in `this->url().encoded_query().size()`.
  284. @par Exception Safety
  285. Strong guarantee.
  286. Calls to allocate may throw.
  287. @return An iterator to the new element.
  288. @param p The param to append.
  289. */
  290. iterator
  291. append(
  292. param_view const& p);
  293. /** Append elements
  294. This function appends the params in
  295. an <em>initializer-list</em> to the view.
  296. <br>
  297. The `end()` iterator is invalidated.
  298. @par Example
  299. @code
  300. url u;
  301. u.params().append({ { "first", "John" }, { "last", "Doe" } });
  302. @endcode
  303. @par Complexity
  304. Linear in `this->url().encoded_query().size()`.
  305. @par Exception Safety
  306. Strong guarantee.
  307. Calls to allocate may throw.
  308. @return An iterator to the first new element.
  309. @param init The list of params to append.
  310. */
  311. iterator
  312. append(
  313. std::initializer_list<
  314. param_view> init);
  315. /** Append elements
  316. This function appends a range of params
  317. to the view.
  318. <br>
  319. The `end()` iterator is invalidated.
  320. @note
  321. The strings referenced by the inputs
  322. must not come from the underlying url,
  323. or else the behavior is undefined.
  324. @par Mandates
  325. @code
  326. std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
  327. @endcode
  328. @par Complexity
  329. Linear in `this->url().encoded_query().size()`.
  330. @par Exception Safety
  331. Strong guarantee.
  332. Calls to allocate may throw.
  333. @return An iterator to the first new element.
  334. @param first, last The range of params
  335. to append.
  336. */
  337. template<class FwdIt>
  338. iterator
  339. append(
  340. FwdIt first, FwdIt last);
  341. //--------------------------------------------
  342. /** Insert elements
  343. This function inserts a param
  344. before the specified position.
  345. <br>
  346. All iterators that are equal to
  347. `before` or come after are invalidated.
  348. @par Complexity
  349. Linear in `this->url().encoded_query().size()`.
  350. @par Exception Safety
  351. Strong guarantee.
  352. Calls to allocate may throw.
  353. @return An iterator to the inserted
  354. element.
  355. @param before An iterator before which
  356. the param is inserted. This may
  357. be equal to `end()`.
  358. @param p The param to insert.
  359. */
  360. iterator
  361. insert(
  362. iterator before,
  363. param_view const& p);
  364. /** Insert elements
  365. This function inserts the params in
  366. an <em>initializer-list</em> before
  367. the specified position.
  368. <br>
  369. All iterators that are equal to
  370. `before` or come after are invalidated.
  371. @note
  372. The strings referenced by the inputs
  373. must not come from the underlying url,
  374. or else the behavior is undefined.
  375. @par Complexity
  376. Linear in `this->url().encoded_query().size()`.
  377. @par Exception Safety
  378. Strong guarantee.
  379. Calls to allocate may throw.
  380. @return An iterator to the first
  381. element inserted, or `before` if
  382. `init.size() == 0`.
  383. @param before An iterator before which
  384. the element is inserted. This may
  385. be equal to `end()`.
  386. @param init The list of params to insert.
  387. */
  388. iterator
  389. insert(
  390. iterator before,
  391. std::initializer_list<
  392. param_view> init);
  393. /** Insert elements
  394. This function inserts a range of
  395. params before the specified position.
  396. <br>
  397. All iterators that are equal to
  398. `before` or come after are invalidated.
  399. @note
  400. The strings referenced by the inputs
  401. must not come from the underlying url,
  402. or else the behavior is undefined.
  403. @par Mandates
  404. @code
  405. std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
  406. @endcode
  407. @par Complexity
  408. Linear in `this->url().encoded_query().size()`.
  409. @par Exception Safety
  410. Strong guarantee.
  411. Calls to allocate may throw.
  412. @return An iterator to the first
  413. element inserted, or `before` if
  414. `first == last`.
  415. @param before An iterator before which
  416. the element is inserted. This may
  417. be equal to `end()`.
  418. @param first, last The range of params
  419. to insert.
  420. */
  421. template<class FwdIt>
  422. iterator
  423. insert(
  424. iterator before,
  425. FwdIt first,
  426. FwdIt last);
  427. //--------------------------------------------
  428. /** Erase elements
  429. This function removes an element from
  430. the container.
  431. <br>
  432. All iterators that are equal to
  433. `pos` or come after are invalidated.
  434. @par Example
  435. @code
  436. url u( "?first=John&last=Doe" );
  437. params_ref::iterator it = u.params().erase( u.params().begin() );
  438. assert( u.encoded_query() == "last=Doe" );
  439. @endcode
  440. @par Complexity
  441. Linear in `this->url().encoded_query().size()`.
  442. @par Exception Safety
  443. Throws nothing.
  444. @return An iterator to one past
  445. the removed element.
  446. @param pos An iterator to the element.
  447. */
  448. iterator
  449. erase(iterator pos) noexcept;
  450. /** Erase elements
  451. This function removes a range of elements
  452. from the container.
  453. <br>
  454. All iterators that are equal to
  455. `first` or come after are invalidated.
  456. @par Complexity
  457. Linear in `this->url().encoded_query().size()`.
  458. @par Exception Safety
  459. Throws nothing.
  460. @return An iterator to one past
  461. the removed range.
  462. @param first, last The range of
  463. elements to erase.
  464. */
  465. iterator
  466. erase(
  467. iterator first,
  468. iterator last) noexcept;
  469. /** Erase elements
  470. <br>
  471. All iterators are invalidated.
  472. @par Postconditions
  473. @code
  474. this->count( key, ic ) == 0
  475. @endcode
  476. @par Complexity
  477. Linear in `this->url().encoded_query().size()`.
  478. @par Exception Safety
  479. Throws nothing.
  480. @return The number of elements removed
  481. from the container.
  482. @param key The key to match.
  483. By default, a case-sensitive
  484. comparison is used.
  485. @param ic An optional parameter. If
  486. the value @ref ignore_case is passed
  487. here, the comparison is
  488. case-insensitive.
  489. */
  490. std::size_t
  491. erase(
  492. core::string_view key,
  493. ignore_case_param ic = {}) noexcept;
  494. //--------------------------------------------
  495. /** Replace elements
  496. This function replaces the contents
  497. of the element at `pos` with the
  498. specified param.
  499. <br>
  500. All iterators that are equal to
  501. `pos` or come after are invalidated.
  502. @par Example
  503. @code
  504. url u( "?first=John&last=Doe" );
  505. u.params().replace( u.params().begin(), { "title", "Mr" });
  506. assert( u.encoded_query() == "title=Mr&last=Doe" );
  507. @endcode
  508. @par Complexity
  509. Linear in `this->url().encoded_query().size()`.
  510. @par Exception Safety
  511. Strong guarantee.
  512. Calls to allocate may throw.
  513. @return An iterator to the element.
  514. @param pos An iterator to the element.
  515. @param p The param to assign.
  516. */
  517. iterator
  518. replace(
  519. iterator pos,
  520. param_view const& p);
  521. /** Replace elements
  522. This function replaces a range of
  523. elements with the params in an
  524. <em>initializer-list</em>.
  525. <br>
  526. All iterators that are equal to
  527. `from` or come after are invalidated.
  528. @note
  529. The strings referenced by the inputs
  530. must not come from the underlying url,
  531. or else the behavior is undefined.
  532. @par Complexity
  533. Linear in `this->url().encoded_query().size()`.
  534. @par Exception Safety
  535. Strong guarantee.
  536. Calls to allocate may throw.
  537. @return An iterator to the first
  538. element inserted, or one past `to` if
  539. `init.size() == 0`.
  540. @param from,to The range of elements
  541. to replace.
  542. @param init The list of params to assign.
  543. */
  544. iterator
  545. replace(
  546. iterator from,
  547. iterator to,
  548. std::initializer_list<
  549. param_view> init);
  550. /** Replace elements
  551. This function replaces a range of
  552. elements with a range of params.
  553. <br>
  554. All iterators that are equal to
  555. `from` or come after are invalidated.
  556. @note
  557. The strings referenced by the inputs
  558. must not come from the underlying url,
  559. or else the behavior is undefined.
  560. @par Mandates
  561. @code
  562. std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
  563. @endcode
  564. @par Complexity
  565. Linear in `this->url().encoded_query().size()`.
  566. @par Exception Safety
  567. Strong guarantee.
  568. Calls to allocate may throw.
  569. @return An iterator to the first
  570. element inserted, or one past `to` if
  571. `first == last`.
  572. @param from,to The range of elements to
  573. replace.
  574. @param first, last The range of params
  575. to assign.
  576. */
  577. template<class FwdIt>
  578. iterator
  579. replace(
  580. iterator from,
  581. iterator to,
  582. FwdIt first,
  583. FwdIt last);
  584. //--------------------------------------------
  585. /** Remove the value on an element
  586. This function removes the value of
  587. an element at the specified position.
  588. After the call returns, `has_value`
  589. for the element is false.
  590. <br>
  591. All iterators that are equal to
  592. `pos` or come after are invalidated.
  593. @par Example
  594. @code
  595. url u( "?first=John&last=Doe" );
  596. u.params().unset( u.params().begin() );
  597. assert( u.encoded_query() == "first&last=Doe" );
  598. @endcode
  599. @par Complexity
  600. Linear in `this->url().encoded_query().size()`.
  601. @par Exception Safety
  602. Throws nothing.
  603. @return An iterator to the element.
  604. @param pos An iterator to the element.
  605. */
  606. iterator
  607. unset(
  608. iterator pos) noexcept;
  609. /** Set a value
  610. This function replaces the value of an
  611. element at the specified position.
  612. <br>
  613. All iterators that are equal to
  614. `pos` or come after are invalidated.
  615. @par Example
  616. @code
  617. url u( "?id=42&id=69" );
  618. u.params().set( u.params().begin(), "none" );
  619. assert( u.encoded_query() == "id=none&id=69" );
  620. @endcode
  621. @par Complexity
  622. Linear in `this->url().encoded_query().size()`.
  623. @par Exception Safety
  624. Strong guarantee.
  625. Calls to allocate may throw.
  626. @return An iterator to the element.
  627. @param pos An iterator to the element.
  628. @param value The value to assign. The
  629. empty string still counts as a value.
  630. That is, `has_value` for the element
  631. is true.
  632. */
  633. iterator
  634. set(
  635. iterator pos,
  636. core::string_view value);
  637. /** Set a value
  638. This function performs one of two
  639. actions depending on the value of
  640. `this->contains( key, ic )`.
  641. @li If key is contained in the view
  642. then one of the matching elements has
  643. its value changed to the specified value.
  644. The remaining elements with a matching
  645. key are erased. Otherwise,
  646. @li If `key` is not contained in the
  647. view, then the function apppends the
  648. param `{ key, value }`.
  649. <br>
  650. All iterators are invalidated.
  651. @par Example
  652. @code
  653. url u( "?id=42&id=69" );
  654. u.params().set( "id", "none" );
  655. assert( u.params().count( "id" ) == 1 );
  656. @endcode
  657. @par Postconditions
  658. @code
  659. this->count( key, ic ) == 1 && this->find( key, ic )->value == value
  660. @endcode
  661. @par Complexity
  662. Linear in `this->url().encoded_query().size()`.
  663. @par Exception Safety
  664. Strong guarantee.
  665. Calls to allocate may throw.
  666. @return An iterator to the appended
  667. or modified element.
  668. @param key The key to match.
  669. By default, a case-sensitive
  670. comparison is used.
  671. @param value The value to assign. The
  672. empty string still counts as a value.
  673. That is, `has_value` for the element
  674. is true.
  675. @param ic An optional parameter. If
  676. the value @ref ignore_case is passed
  677. here, the comparison is
  678. case-insensitive.
  679. */
  680. iterator
  681. set(
  682. core::string_view key,
  683. core::string_view value,
  684. ignore_case_param ic = {});
  685. //--------------------------------------------
  686. private:
  687. template<class FwdIt>
  688. void
  689. assign(FwdIt first, FwdIt last,
  690. std::forward_iterator_tag);
  691. // Doxygen cannot render ` = delete`
  692. template<class FwdIt>
  693. void
  694. assign(FwdIt first, FwdIt last,
  695. std::input_iterator_tag) = delete;
  696. template<class FwdIt>
  697. iterator
  698. insert(
  699. iterator before,
  700. FwdIt first,
  701. FwdIt last,
  702. std::forward_iterator_tag);
  703. // Doxygen cannot render ` = delete`
  704. template<class FwdIt>
  705. iterator
  706. insert(
  707. iterator before,
  708. FwdIt first,
  709. FwdIt last,
  710. std::input_iterator_tag) = delete;
  711. };
  712. } // urls
  713. } // boost
  714. // This is in <boost/url/url_base.hpp>
  715. //
  716. // #include <boost/url/impl/params_ref.hpp>
  717. #endif