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