Line data Source code
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 :
11 : #ifndef BOOST_URL_PARAMS_REF_HPP
12 : #define BOOST_URL_PARAMS_REF_HPP
13 :
14 : #include <boost/url/detail/config.hpp>
15 : #include <boost/url/ignore_case.hpp>
16 : #include <boost/url/params_base.hpp>
17 : #include <initializer_list>
18 : #include <iterator>
19 :
20 : namespace boost {
21 : namespace urls {
22 :
23 : #ifndef BOOST_URL_DOCS
24 : class url_base;
25 : class params_view;
26 : #endif
27 :
28 : /** Mutable decoded query parameter proxy
29 :
30 : This container presents the decoded query
31 : parameters of a @ref url_base as a bidirectional
32 : range whose modifying operations update the
33 : underlying URL in-place. It references (but
34 : does not own) the character buffer, so the
35 : referenced URL must stay alive while the proxy
36 : is used.
37 :
38 : <br>
39 :
40 : Percent escapes in strings returned when
41 : dereferencing iterators are automatically
42 : decoded.
43 : Reserved characters in strings supplied
44 : to modifier functions are automatically
45 : percent-escaped.
46 :
47 : @par Example
48 : @code
49 : url u( "?first=John&last=Doe" );
50 :
51 : params_ref p = u.params();
52 : @endcode
53 :
54 : @par Iterator Invalidation
55 : Changes to the underlying character buffer
56 : can invalidate iterators which reference it.
57 : Modifications made through the container
58 : invalidate some or all iterators:
59 : <br>
60 :
61 : @li @ref append : Only `end()`.
62 :
63 : @li @ref assign, @ref clear,
64 : `operator=` : All elements.
65 :
66 : @li @ref erase : Erased elements and all
67 : elements after (including `end()`).
68 :
69 : @li @ref insert : All elements at or after
70 : the insertion point (including `end()`).
71 :
72 : @li @ref replace, @ref set : Modified
73 : elements and all elements
74 : after (including `end()`).
75 :
76 : @par Reads vs. writes
77 : Although this is a mutable proxy, all
78 : observer helpers inherited from
79 : @ref params_base (such as @ref contains,
80 : @ref find, and @ref get_or) operate in the
81 : same way as they do on @ref params_view:
82 : they perform their lookup against the
83 : current contents of the referenced URL
84 : without modifying it.
85 : */
86 : class BOOST_URL_DECL params_ref
87 : : public params_base
88 : {
89 : friend class url_base;
90 :
91 : url_base* u_ = nullptr;
92 :
93 : params_ref(
94 : url_base& u,
95 : encoding_opts opt) noexcept;
96 :
97 : public:
98 : //--------------------------------------------
99 : //
100 : // Special Members
101 : //
102 : //--------------------------------------------
103 :
104 : /** Constructor
105 :
106 : After construction, both views
107 : reference the same url. Ownership is not
108 : transferred; the caller is responsible
109 : for ensuring the lifetime of the url
110 : extends until it is no longer
111 : referenced.
112 :
113 : @par Postconditions
114 : @code
115 : &this->url() == &other.url()
116 : @endcode
117 :
118 : @par Complexity
119 : Constant.
120 :
121 : @par Exception Safety
122 : Throws nothing.
123 :
124 : @param other The other view.
125 : */
126 : params_ref(
127 : params_ref const& other) = default;
128 :
129 : /** Constructor
130 :
131 : After construction, both views will
132 : reference the same url but this
133 : instance will use the specified
134 : @ref encoding_opts when the values
135 : are decoded.
136 :
137 : Ownership is not transferred; the
138 : caller is responsible for ensuring
139 : the lifetime of the url extends
140 : until it is no longer referenced.
141 :
142 : @par Postconditions
143 : @code
144 : &this->url() == &other.url()
145 : @endcode
146 :
147 : @par Complexity
148 : Constant.
149 :
150 : @par Exception Safety
151 : Throws nothing.
152 :
153 : @param other The other view.
154 : @param opt The options for decoding. If
155 : this parameter is omitted, `space_as_plus`
156 : is used.
157 :
158 : */
159 : params_ref(
160 : params_ref const& other,
161 : encoding_opts opt) noexcept;
162 :
163 : /** Assignment
164 :
165 : The previous contents of this are
166 : replaced by the contents of `other.
167 :
168 : <br>
169 : All iterators are invalidated.
170 :
171 : @note
172 : The strings referenced by `other`
173 : must not come from the underlying url,
174 : or else the behavior is undefined.
175 :
176 : @par Effects
177 : @code
178 : this->assign( other.begin(), other.end() );
179 : @endcode
180 :
181 : @par Complexity
182 : Linear in `other.buffer().size()`.
183 :
184 : @par Exception Safety
185 : Strong guarantee.
186 : Calls to allocate may throw.
187 :
188 : @param other The params to assign.
189 : @return `*this`
190 : */
191 : params_ref&
192 : operator=(
193 : params_ref const& other);
194 :
195 : /** Assignment
196 :
197 : After assignment, the previous contents
198 : of the query parameters are replaced by
199 : the contents of the initializer-list.
200 :
201 : @par Preconditions
202 : None of character buffers referenced by
203 : `init` may overlap the character buffer of
204 : the underlying url, or else the behavior
205 : is undefined.
206 :
207 : @par Effects
208 : @code
209 : this->assign( init );
210 : @endcode
211 :
212 : @par Complexity
213 : Linear in `init.size()`.
214 :
215 : @par Exception Safety
216 : Strong guarantee.
217 : Calls to allocate may throw.
218 :
219 : @param init The list of params to assign.
220 : @return `*this`
221 : */
222 : params_ref&
223 : operator=(
224 : std::initializer_list<
225 : param_view> init);
226 :
227 : /** Conversion
228 :
229 : @return A view of the query parameters.
230 : */
231 : operator
232 : params_view() const noexcept;
233 :
234 : //--------------------------------------------
235 : //
236 : // Observers
237 : //
238 : //--------------------------------------------
239 :
240 : /** Return the referenced url
241 :
242 : This function returns the url referenced
243 : by the view.
244 :
245 : @par Example
246 : @code
247 : url u( "?key=value" );
248 :
249 : assert( &u.segments().url() == &u );
250 : @endcode
251 :
252 : @par Exception Safety
253 : @code
254 : Throws nothing.
255 : @endcode
256 :
257 : @return A reference to the url.
258 : */
259 : url_base&
260 10 : url() const noexcept
261 : {
262 10 : return *u_;
263 : }
264 :
265 : //--------------------------------------------
266 : //
267 : // Modifiers
268 : //
269 : //--------------------------------------------
270 :
271 : /** Clear the contents of the container
272 :
273 : <br>
274 : All iterators are invalidated.
275 :
276 : @par Effects
277 : @code
278 : this->url().remove_query();
279 : @endcode
280 :
281 : @par Postconditions
282 : @code
283 : this->empty() == true && this->url().has_query() == false
284 : @endcode
285 :
286 : @par Complexity
287 : Constant.
288 :
289 : @par Exception Safety
290 : Throws nothing.
291 : */
292 : void
293 : clear() noexcept;
294 :
295 : //--------------------------------------------
296 :
297 : /** Assign elements
298 :
299 : This function replaces the entire
300 : contents of the view with the params
301 : in the <em>initializer-list</em>.
302 :
303 : <br>
304 : All iterators are invalidated.
305 :
306 : @note
307 : The strings referenced by the inputs
308 : must not come from the underlying url,
309 : or else the behavior is undefined.
310 :
311 : @par Example
312 : @code
313 : url u;
314 :
315 : u.params().assign( {{ "first", "John" }, { "last", "Doe" }} );
316 : @endcode
317 :
318 : @par Complexity
319 : Linear in `init.size()`.
320 :
321 : @par Exception Safety
322 : Strong guarantee.
323 : Calls to allocate may throw.
324 :
325 : @param init The list of params to assign.
326 : */
327 : void
328 : assign(
329 : std::initializer_list<
330 : param_view> init);
331 :
332 : /** Assign elements
333 :
334 : This function replaces the entire
335 : contents of the view with the params
336 : in the range.
337 :
338 : <br>
339 : All iterators are invalidated.
340 :
341 : @note
342 : The strings referenced by the inputs
343 : must not come from the underlying url,
344 : or else the behavior is undefined.
345 :
346 : @par Mandates
347 : @code
348 : std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
349 : @endcode
350 :
351 : @par Complexity
352 : Linear in the size of the range.
353 :
354 : @par Exception Safety
355 : Strong guarantee.
356 : Calls to allocate may throw.
357 :
358 : @param first The first element to assign.
359 : @param last One past the last element to assign.
360 : */
361 : template<class FwdIt>
362 : void
363 : assign(FwdIt first, FwdIt last);
364 :
365 : //--------------------------------------------
366 :
367 : /** Append elements
368 :
369 : This function appends a param to the view.
370 :
371 : <br>
372 : The `end()` iterator is invalidated.
373 :
374 : @par Example
375 : @code
376 : url u;
377 :
378 : u.params().append( { "first", "John" } );
379 : @endcode
380 :
381 : @par Complexity
382 : Linear in `this->url().encoded_query().size()`.
383 :
384 : @par Exception Safety
385 : Strong guarantee.
386 : Calls to allocate may throw.
387 :
388 : @return An iterator to the new element.
389 :
390 : @param p The param to append.
391 : */
392 : iterator
393 : append(
394 : param_view const& p);
395 :
396 : /** Append elements
397 :
398 : This function appends the params in
399 : an <em>initializer-list</em> to the view.
400 :
401 : <br>
402 : The `end()` iterator is invalidated.
403 :
404 : @par Example
405 : @code
406 : url u;
407 :
408 : u.params().append({ { "first", "John" }, { "last", "Doe" } });
409 : @endcode
410 :
411 : @par Complexity
412 : Linear in `this->url().encoded_query().size()`.
413 :
414 : @par Exception Safety
415 : Strong guarantee.
416 : Calls to allocate may throw.
417 :
418 : @return An iterator to the first new element.
419 :
420 : @param init The list of params to append.
421 : */
422 : iterator
423 : append(
424 : std::initializer_list<
425 : param_view> init);
426 :
427 : /** Append elements
428 :
429 : This function appends a range of params
430 : to the view.
431 :
432 : <br>
433 : The `end()` iterator is invalidated.
434 :
435 : @note
436 : The strings referenced by the inputs
437 : must not come from the underlying url,
438 : or else the behavior is undefined.
439 :
440 : @par Mandates
441 : @code
442 : std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
443 : @endcode
444 :
445 : @par Complexity
446 : Linear in `this->url().encoded_query().size()`.
447 :
448 : @par Exception Safety
449 : Strong guarantee.
450 : Calls to allocate may throw.
451 :
452 : @param first The first element to append.
453 : @param last One past the last element to append.
454 : @return An iterator to the first new element.
455 : */
456 : template<class FwdIt>
457 : iterator
458 : append(
459 : FwdIt first, FwdIt last);
460 :
461 : //--------------------------------------------
462 :
463 : /** Insert elements
464 :
465 : This function inserts a param
466 : before the specified position.
467 :
468 : <br>
469 : All iterators that are equal to
470 : `before` or come after are invalidated.
471 :
472 : @par Complexity
473 : Linear in `this->url().encoded_query().size()`.
474 :
475 : @par Exception Safety
476 : Strong guarantee.
477 : Calls to allocate may throw.
478 :
479 : @return An iterator to the inserted
480 : element.
481 :
482 : @param before An iterator before which
483 : the param is inserted. This may
484 : be equal to `end()`.
485 :
486 : @param p The param to insert.
487 : */
488 : iterator
489 : insert(
490 : iterator before,
491 : param_view const& p);
492 :
493 : /** Insert elements
494 :
495 : This function inserts the params in
496 : an <em>initializer-list</em> before
497 : the specified position.
498 :
499 : <br>
500 : All iterators that are equal to
501 : `before` or come after are invalidated.
502 :
503 : @note
504 : The strings referenced by the inputs
505 : must not come from the underlying url,
506 : or else the behavior is undefined.
507 :
508 : @par Complexity
509 : Linear in `this->url().encoded_query().size()`.
510 :
511 : @par Exception Safety
512 : Strong guarantee.
513 : Calls to allocate may throw.
514 :
515 : @return An iterator to the first
516 : element inserted, or `before` if
517 : `init.size() == 0`.
518 :
519 : @param before An iterator before which
520 : the element is inserted. This may
521 : be equal to `end()`.
522 :
523 : @param init The list of params to insert.
524 : */
525 : iterator
526 : insert(
527 : iterator before,
528 : std::initializer_list<
529 : param_view> init);
530 :
531 : /** Insert elements
532 :
533 : This function inserts a range of
534 : params before the specified position.
535 :
536 : <br>
537 : All iterators that are equal to
538 : `before` or come after are invalidated.
539 :
540 : @note
541 : The strings referenced by the inputs
542 : must not come from the underlying url,
543 : or else the behavior is undefined.
544 :
545 : @par Mandates
546 : @code
547 : std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
548 : @endcode
549 :
550 : @par Complexity
551 : Linear in `this->url().encoded_query().size()`.
552 :
553 : @par Exception Safety
554 : Strong guarantee.
555 : Calls to allocate may throw.
556 :
557 : @return An iterator to the first
558 : element inserted, or `before` if
559 : `first == last`.
560 :
561 : @param before An iterator before which
562 : the element is inserted. This may
563 : be equal to `end()`.
564 : @param first The first element to insert.
565 : @param last One past the last element to insert.
566 : @return An iterator to the first element inserted, or `before` if `first == last`.
567 : */
568 : template<class FwdIt>
569 : iterator
570 : insert(
571 : iterator before,
572 : FwdIt first,
573 : FwdIt last);
574 :
575 : //--------------------------------------------
576 :
577 : /** Erase elements
578 :
579 : This function removes an element from
580 : the container.
581 :
582 : <br>
583 : All iterators that are equal to
584 : `pos` or come after are invalidated.
585 :
586 : @par Example
587 : @code
588 : url u( "?first=John&last=Doe" );
589 :
590 : params_ref::iterator it = u.params().erase( u.params().begin() );
591 :
592 : assert( u.encoded_query() == "last=Doe" );
593 : @endcode
594 :
595 : @par Complexity
596 : Linear in `this->url().encoded_query().size()`.
597 :
598 : @par Exception Safety
599 : Throws nothing.
600 :
601 : @return An iterator to one past
602 : the removed element.
603 :
604 : @param pos An iterator to the element.
605 : */
606 : iterator
607 : erase(iterator pos) noexcept;
608 :
609 : /** Erase elements
610 :
611 : This function removes a range of elements
612 : from the container.
613 :
614 : <br>
615 : All iterators that are equal to
616 : `first` or come after are invalidated.
617 :
618 : @par Complexity
619 : Linear in `this->url().encoded_query().size()`.
620 :
621 : @par Exception Safety
622 : Throws nothing.
623 :
624 : @param first The first element to remove.
625 : @param last One past the last element to remove.
626 : @return An iterator to one past the removed range.
627 : */
628 : iterator
629 : erase(
630 : iterator first,
631 : iterator last) noexcept;
632 :
633 : /** Erase elements
634 :
635 : <br>
636 : All iterators are invalidated.
637 :
638 : @par Postconditions
639 : @code
640 : this->count( key, ic ) == 0
641 : @endcode
642 :
643 : @par Complexity
644 : Linear in `this->url().encoded_query().size()`.
645 :
646 : @par Exception Safety
647 : Throws nothing.
648 :
649 : @return The number of elements removed
650 : from the container.
651 :
652 : @param key The key to match.
653 : By default, a case-sensitive
654 : comparison is used.
655 :
656 : @param ic An optional parameter. If
657 : the value @ref ignore_case is passed
658 : here, the comparison is
659 : case-insensitive.
660 : */
661 : std::size_t
662 : erase(
663 : core::string_view key,
664 : ignore_case_param ic = {}) noexcept;
665 :
666 : //--------------------------------------------
667 :
668 : /** Replace elements
669 :
670 : This function replaces the contents
671 : of the element at `pos` with the
672 : specified param.
673 :
674 : <br>
675 : All iterators that are equal to
676 : `pos` or come after are invalidated.
677 :
678 : @par Example
679 : @code
680 : url u( "?first=John&last=Doe" );
681 :
682 : u.params().replace( u.params().begin(), { "title", "Mr" });
683 :
684 : assert( u.encoded_query() == "title=Mr&last=Doe" );
685 : @endcode
686 :
687 : @par Complexity
688 : Linear in `this->url().encoded_query().size()`.
689 :
690 : @par Exception Safety
691 : Strong guarantee.
692 : Calls to allocate may throw.
693 :
694 : @return An iterator to the element.
695 :
696 : @param pos An iterator to the element.
697 :
698 : @param p The param to assign.
699 : */
700 : iterator
701 : replace(
702 : iterator pos,
703 : param_view const& p);
704 :
705 : /** Replace elements
706 :
707 : This function replaces a range of
708 : elements with the params in an
709 : <em>initializer-list</em>.
710 :
711 : <br>
712 : All iterators that are equal to
713 : `from` or come after are invalidated.
714 :
715 : @note
716 : The strings referenced by the inputs
717 : must not come from the underlying url,
718 : or else the behavior is undefined.
719 :
720 : @par Complexity
721 : Linear in `this->url().encoded_query().size()`.
722 :
723 : @par Exception Safety
724 : Strong guarantee.
725 : Calls to allocate may throw.
726 :
727 : @return An iterator to the first
728 : element inserted, or one past `to` if
729 : `init.size() == 0`.
730 :
731 : @param from,to The range of elements
732 : to replace.
733 :
734 : @param init The list of params to assign.
735 : */
736 : iterator
737 : replace(
738 : iterator from,
739 : iterator to,
740 : std::initializer_list<
741 : param_view> init);
742 :
743 : /** Replace elements
744 :
745 : This function replaces a range of
746 : elements with a range of params.
747 :
748 : <br>
749 : All iterators that are equal to
750 : `from` or come after are invalidated.
751 :
752 : @note
753 : The strings referenced by the inputs
754 : must not come from the underlying url,
755 : or else the behavior is undefined.
756 :
757 : @par Mandates
758 : @code
759 : std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
760 : @endcode
761 :
762 : @par Complexity
763 : Linear in `this->url().encoded_query().size()`.
764 :
765 : @par Exception Safety
766 : Strong guarantee.
767 : Calls to allocate may throw.
768 :
769 : @return An iterator to the first
770 : element inserted, or one past `to` if
771 : `first == last`.
772 :
773 : @param from The first element to replace.
774 : @param to One past the last element to replace.
775 : @param first The first element to insert.
776 : @param last One past the last element to insert.
777 : @return An iterator to the first element inserted, or one past `to` if `first == last`.
778 : */
779 : template<class FwdIt>
780 : iterator
781 : replace(
782 : iterator from,
783 : iterator to,
784 : FwdIt first,
785 : FwdIt last);
786 :
787 : //--------------------------------------------
788 :
789 : /** Remove the value on an element
790 :
791 : This function removes the value of
792 : an element at the specified position.
793 : After the call returns, `has_value`
794 : for the element is false.
795 :
796 : <br>
797 : All iterators that are equal to
798 : `pos` or come after are invalidated.
799 :
800 : @par Example
801 : @code
802 : url u( "?first=John&last=Doe" );
803 :
804 : u.params().unset( u.params().begin() );
805 :
806 : assert( u.encoded_query() == "first&last=Doe" );
807 : @endcode
808 :
809 : @par Complexity
810 : Linear in `this->url().encoded_query().size()`.
811 :
812 : @par Exception Safety
813 : Throws nothing.
814 :
815 : @return An iterator to the element.
816 :
817 : @param pos An iterator to the element.
818 : */
819 : iterator
820 : unset(
821 : iterator pos) noexcept;
822 :
823 : /** Set a value
824 :
825 : This function replaces the value of an
826 : element at the specified position.
827 :
828 : <br>
829 : All iterators that are equal to
830 : `pos` or come after are invalidated.
831 :
832 : @par Example
833 : @code
834 : url u( "?id=42&id=69" );
835 :
836 : u.params().set( u.params().begin(), "none" );
837 :
838 : assert( u.encoded_query() == "id=none&id=69" );
839 : @endcode
840 :
841 : @par Complexity
842 : Linear in `this->url().encoded_query().size()`.
843 :
844 : @par Exception Safety
845 : Strong guarantee.
846 : Calls to allocate may throw.
847 :
848 : @return An iterator to the element.
849 :
850 : @param pos An iterator to the element.
851 :
852 : @param value The value to assign. The
853 : empty string still counts as a value.
854 : That is, `has_value` for the element
855 : is true.
856 : */
857 : iterator
858 : set(
859 : iterator pos,
860 : core::string_view value);
861 :
862 : /** Set a value
863 :
864 : This function performs one of two
865 : actions depending on the value of
866 : `this->contains( key, ic )`.
867 :
868 : @li If key is contained in the view
869 : then one of the matching elements has
870 : its value changed to the specified value.
871 : The remaining elements with a matching
872 : key are erased. Otherwise,
873 :
874 : @li If `key` is not contained in the
875 : view, then the function apppends the
876 : param `{ key, value }`.
877 :
878 : <br>
879 : All iterators are invalidated.
880 :
881 : @par Example
882 : @code
883 : url u( "?id=42&id=69" );
884 :
885 : u.params().set( "id", "none" );
886 :
887 : assert( u.params().count( "id" ) == 1 );
888 : @endcode
889 :
890 : @par Postconditions
891 : @code
892 : this->count( key, ic ) == 1 && this->find( key, ic )->value == value
893 : @endcode
894 :
895 : @par Complexity
896 : Linear in `this->url().encoded_query().size()`.
897 :
898 : @par Exception Safety
899 : Strong guarantee.
900 : Calls to allocate may throw.
901 :
902 : @return An iterator to the appended
903 : or modified element.
904 :
905 : @param key The key to match.
906 : By default, a case-sensitive
907 : comparison is used.
908 :
909 : @param value The value to assign. The
910 : empty string still counts as a value.
911 : That is, `has_value` for the element
912 : is true.
913 :
914 : @param ic An optional parameter. If
915 : the value @ref ignore_case is passed
916 : here, the comparison is
917 : case-insensitive.
918 : */
919 : iterator
920 : set(
921 : core::string_view key,
922 : core::string_view value,
923 : ignore_case_param ic = {});
924 :
925 : //--------------------------------------------
926 :
927 : private:
928 : template<class FwdIt>
929 : void
930 : assign(FwdIt first, FwdIt last,
931 : std::forward_iterator_tag);
932 :
933 : // Doxygen cannot render ` = delete`
934 : template<class FwdIt>
935 : void
936 : assign(FwdIt first, FwdIt last,
937 : std::input_iterator_tag) = delete;
938 :
939 : template<class FwdIt>
940 : iterator
941 : insert(
942 : iterator before,
943 : FwdIt first,
944 : FwdIt last,
945 : std::forward_iterator_tag);
946 :
947 : // Doxygen cannot render ` = delete`
948 : template<class FwdIt>
949 : iterator
950 : insert(
951 : iterator before,
952 : FwdIt first,
953 : FwdIt last,
954 : std::input_iterator_tag) = delete;
955 : };
956 :
957 : } // urls
958 : } // boost
959 :
960 : // This is in <boost/url/url_base.hpp>
961 : //
962 : // #include <boost/url/impl/params_ref.hpp>
963 :
964 : #endif
|