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