params_ref.hpp 22 KB

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