GCC Code Coverage Report


Directory: libs/url/
File: include/boost/url/param.hpp
Date: 2025-11-10 19:06:22
Exec Total Coverage
Lines: 90 90 100.0%
Functions: 52 53 98.1%
Branches: 14 16 87.5%

Line Branch Exec Source
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_PARAM_HPP
12 #define BOOST_URL_PARAM_HPP
13
14 #include <boost/url/detail/config.hpp>
15 #include <boost/url/detail/optional_string.hpp>
16 #include <boost/url/pct_string_view.hpp>
17 #include <cstddef>
18 #include <string>
19
20 namespace boost {
21 namespace urls {
22
23 #ifndef BOOST_URL_DOCS
24 struct param_pct_view;
25 struct param_view;
26 #endif
27
28 /** The type of @ref no_value
29 */
30 struct no_value_t
31 {
32 };
33
34 /** Constant indicating no value in a param
35 */
36 constexpr no_value_t no_value{};
37
38 //------------------------------------------------
39
40 /** A query parameter
41
42 Objects of this type represent a single key
43 and value pair in a query string where a key
44 is always present and may be empty, while the
45 presence of a value is indicated by
46 @ref has_value equal to true.
47 An empty value is distinct from no value.
48
49 Depending on where the object was obtained,
50 the strings may or may not contain percent
51 escapes.
52
53 For most usages, key comparisons are
54 case-sensitive and duplicate keys in
55 a query are possible. However, it is
56 the authority that has final control
57 over how the query is interpreted.
58
59 @par BNF
60 @code
61 query-params = query-param *( "&" query-param )
62 query-param = key [ "=" value ]
63 key = *qpchar
64 value = *( qpchar / "=" )
65 @endcode
66
67 @par Specification
68 @li <a href="https://en.wikipedia.org/wiki/Query_string"
69 >Query string (Wikipedia)</a>
70
71 @see
72 @ref param_view,
73 @ref param_pct_view.
74 */
75 struct param
76 {
77 /** The key
78
79 For most usages, key comparisons are
80 case-sensitive and duplicate keys in
81 a query are possible. However, it is
82 the authority that has final control
83 over how the query is interpreted.
84 */
85 std::string key;
86
87 /** The value
88
89 The presence of a value is indicated by
90 @ref has_value equal to true.
91 An empty value is distinct from no value.
92 */
93 std::string value;
94
95 /** True if a value is present
96
97 The presence of a value is indicated by
98 `has_value == true`.
99 An empty value is distinct from no value.
100 */
101 bool has_value = false;
102
103 /** Constructor
104
105 Default constructed query parameters
106 have an empty key and no value.
107
108 @par Example
109 @code
110 param qp;
111 @endcode
112
113 @par Postconditions
114 @code
115 this->key == "" && this->value == "" && this->has_value == false
116 @endcode
117
118 @par Complexity
119 Constant.
120
121 @par Exception Safety
122 Throws nothing.
123 */
124 6 param() = default;
125
126 /** Constructor
127
128 Upon construction, this acquires
129 ownership of the members of other
130 via move construction. The moved
131 from object is as if default
132 constructed.
133
134 @par Complexity
135 Constant.
136
137 @par Exception Safety
138 Throws nothing.
139
140 @param other The object to construct from.
141 */
142 1 param(param&& other) noexcept
143 1 : key(std::move(other.key))
144 1 , value(std::move(other.value))
145 1 , has_value(other.has_value)
146 {
147 #ifdef BOOST_URL_COW_STRINGS
148 // for copy-on-write std::string
149 other.key.clear();
150 other.value.clear();
151 #endif
152 1 other.has_value = false;
153 1 }
154
155 /** Constructor
156
157 Upon construction, this becomes a copy
158 of `other`.
159
160 @par Postconditions
161 @code
162 this->key == other.key && this->value == other.value && this->has_value == other.has_value
163 @endcode
164
165 @par Complexity
166 Linear in `other.key.size() + other.value.size()`.
167
168 @par Exception Safety
169 Calls to allocate may throw.
170
171 @param other The object to construct from.
172 @return A reference to this object.
173 */
174
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 param(param const& other) = default;
175
176 /** Assignment
177
178 Upon assignment, this acquires
179 ownership of the members of other
180 via move assignment. The moved
181 from object is as if default
182 constructed.
183
184 @par Complexity
185 Constant.
186
187 @par Exception Safety
188 Throws nothing.
189
190
191 @param other The object to assign from.
192 @return A reference to this object.
193 */
194 param&
195 3 operator=(param&& other) noexcept
196 {
197 3 key = std::move(other.key);
198 3 value = std::move(other.value);
199 3 has_value = other.has_value;
200 #ifdef BOOST_URL_COW_STRINGS
201 // for copy-on-write std::string
202 other.key.clear();
203 other.value.clear();
204 #endif
205 3 other.has_value = false;
206 3 return *this;
207 }
208
209 /** Assignment
210
211 Upon assignment, this becomes a copy
212 of `other`.
213
214 @par Postconditions
215 @code
216 this->key == other.key && this->value == other.value && this->has_value == other.has_value
217 @endcode
218
219 @par Complexity
220 Linear in `other.key.size() + other.value.size()`.
221
222 @par Exception Safety
223 Calls to allocate may throw.
224
225
226 @param other The object to assign from.
227 @return A reference to this object.
228 */
229 1 param& operator=(
230 param const& other) = default;
231
232 //--------------------------------------------
233
234 /** Constructor
235
236 This constructs a parameter with a key
237 and value.
238
239 No validation is performed on the strings.
240 Ownership of the key and value is acquired
241 by making copies.
242
243 @par Example
244 @code
245 param qp( "key", "value" );
246 @endcode
247
248 @code
249 param qp( "key", optional<core::string_view>("value") );
250 @endcode
251
252 @code
253 param qp( "key", boost::none );
254 @endcode
255
256 @code
257 param qp( "key", nullptr );
258 @endcode
259
260 @code
261 param qp( "key", no_value );
262 @endcode
263
264 @par Postconditions
265 @code
266 this->key == key && this->value == value && this->has_value == true
267 @endcode
268
269 @par Complexity
270 Linear in `key.size() + value.size()`.
271
272 @par Exception Safety
273 Calls to allocate may throw.
274
275 @tparam OptionalString An optional string
276 type, such as `core::string_view`,
277 `std::nullptr`, @ref no_value_t, or
278 `optional<core::string_view>`.
279
280 @param key The key to set.
281 @param value The value to set.
282 */
283 template <class OptionalString>
284 32 param(
285 core::string_view key,
286 OptionalString const& value)
287
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
32 : param(key, detail::get_optional_string(value))
288 {
289 32 }
290
291 /** Assignment
292
293 The members of `other` are copied,
294 re-using already existing string capacity.
295
296 @par Postconditions
297 @code
298 this->key == other.key && this->value == other.value && this->has_value == other.has_value
299 @endcode
300
301 @par Complexity
302 Linear in `other.key.size() + other.value.size()`.
303
304 @par Exception Safety
305 Calls to allocate may throw.
306
307 @param other The parameter to copy.
308 @return A reference to this object.
309 */
310 param&
311 operator=(param_view const& other);
312
313 /** Assignment
314
315 The members of `other` are copied,
316 re-using already existing string capacity.
317
318 @par Postconditions
319 @code
320 this->key == other.key && this->value == other.value && this->has_value == other.has_value
321 @endcode
322
323 @par Complexity
324 Linear in `other.key.size() + other.value.size()`.
325
326 @par Exception Safety
327 Calls to allocate may throw.
328
329 @param other The parameter to copy.
330 @return A reference to this object.
331 */
332 param&
333 operator=(param_pct_view const& other);
334
335 /** Arrow support
336
337 This operator returns the address of the
338 object so that it can be used in pointer
339 contexts.
340
341 @return A pointer to the object.
342
343 */
344 param const*
345 1 operator->() const noexcept
346 {
347 1 return this;
348 }
349
350 /** Aggregate construction
351
352 @param key The key to set.
353 @param value The value to set.
354 @param has_value True if a value is present.
355 */
356 797 param(
357 core::string_view key,
358 core::string_view value,
359 bool has_value) noexcept
360 797 : key(key)
361 797 , value(has_value
362
2/2
✓ Branch 0 taken 623 times.
✓ Branch 1 taken 174 times.
797 ? value
363 : core::string_view())
364 797 , has_value(has_value)
365 {
366 797 }
367
368 private:
369 16 param(
370 core::string_view key,
371 detail::optional_string const& value)
372 16 : param(key, value.s, value.b)
373 {
374 16 }
375 };
376
377 //------------------------------------------------
378
379 /** A view of a query parameter
380
381 Objects of this type represent a single key
382 and value pair in a query string where a key
383 is always present and may be empty, while the
384 presence of a value is indicated by
385 @ref has_value equal to true.
386 An empty value is distinct from no value.
387
388 Depending on where the object was obtained,
389 the strings may or may not contain percent
390 escapes. Some functions and objects might
391 expect encoded strings in this view, while
392 others expect decoded strings. The caller
393 should be aware of the context in which
394 the object will be used.
395
396 For most usages, key comparisons are
397 case-sensitive and duplicate keys in
398 a query are possible. However, it is
399 the authority that has final control
400 over how the query is interpreted.
401
402 <br>
403
404 Keys and values in this object reference
405 external character buffers.
406 Ownership of the buffers is not transferred;
407 the caller is responsible for ensuring that
408 the assigned buffers remain valid until
409 they are no longer referenced.
410
411 @par BNF
412 @code
413 query-params = query-param *( "&" query-param )
414 query-param = key [ "=" value ]
415 key = *qpchar
416 value = *( qpchar / "=" )
417 @endcode
418
419 @par Specification
420 @li <a href="https://en.wikipedia.org/wiki/Query_string"
421 >Query string (Wikipedia)</a>
422
423 @see
424 @ref param,
425 @ref param_pct_view.
426 */
427 struct param_view
428 {
429 /** The key
430
431 For most usages, key comparisons are
432 case-sensitive and duplicate keys in
433 a query are possible. However, it is
434 the authority that has final control
435 over how the query is interpreted.
436 */
437 core::string_view key;
438
439 /** The value
440
441 The presence of a value is indicated by
442 @ref has_value equal to true.
443 An empty value is distinct from no value.
444 */
445 core::string_view value;
446
447 /** True if a value is present
448
449 The presence of a value is indicated by
450 `has_value == true`.
451 An empty value is distinct from no value.
452 */
453 bool has_value = false;
454
455 //--------------------------------------------
456
457 /** Constructor
458
459 Default constructed query parameters
460 have an empty key and no value.
461
462 @par Example
463 @code
464 param_view qp;
465 @endcode
466
467 @par Postconditions
468 @code
469 this->key == "" && this->value == "" && this->has_value == false
470 @endcode
471
472 @par Complexity
473 Constant.
474
475 @par Exception Safety
476 Throws nothing.
477 */
478 param_view() = default;
479
480 /** Constructor
481
482 This constructs a parameter with a key
483 and value.
484 No validation is performed on the strings.
485 The new key and value reference
486 the same corresponding underlying
487 character buffers.
488 Ownership of the buffers is not transferred;
489 the caller is responsible for ensuring that
490 the assigned buffers remain valid until
491 they are no longer referenced.
492
493 @par Example
494 @code
495 param_view qp( "key", "value" );
496 @endcode
497
498 @par Postconditions
499 @code
500 this->key.data() == key.data() && this->value.data() == value.data() && this->has_value == true
501 @endcode
502
503 @par Complexity
504 Constant.
505
506 @par Exception Safety
507 Throws nothing.
508
509 @tparam OptionalString An optional string
510 type, such as `core::string_view`,
511 `std::nullptr`, @ref no_value_t, or
512 `optional<core::string_view>`.
513
514 @param key The key to set.
515 @param value The value to set.
516 */
517 template <class OptionalString>
518 344 param_view(
519 core::string_view key,
520 OptionalString const& value) noexcept
521 344 : param_view(key, detail::get_optional_string(value))
522 {
523 344 }
524
525 /** Constructor
526
527 This function constructs a param
528 which references the character buffers
529 representing the key and value in another
530 container.
531 Ownership of the buffers is not transferred;
532 the caller is responsible for ensuring that
533 the assigned buffers remain valid until
534 they are no longer referenced.
535
536 @par Example
537 @code
538 param qp( "key", "value" );
539 param_view qpv( qp );
540 @endcode
541
542 @par Postconditions
543 @code
544 this->key == key && this->value == value && this->has_value == other.has_value
545 @endcode
546
547 @par Complexity
548 Constant.
549
550 @par Exception Safety
551 Throws nothing.
552
553 @param other The param to reference
554 */
555 754 param_view(
556 param const& other) noexcept
557 754 : param_view(
558 754 other.key,
559 754 other.value,
560 754 other.has_value)
561 {
562 754 }
563
564 /** Conversion
565
566 This function performs a conversion from
567 a reference-like query parameter to one
568 retaining ownership of the strings by
569 making a copy.
570 No validation is performed on the strings.
571
572 @par Complexity
573 Linear in `this->key.size() + this->value.size()`.
574
575 @par Exception Safety
576 Calls to allocate may throw.
577
578 @return A new query parameter.
579 */
580 explicit
581 4 operator
582 param()
583 {
584 4 return { key, value, has_value };
585 }
586
587 /** Arrow support
588
589 This operator returns the address of the
590 object so that it can be used in pointer
591 contexts.
592
593 @return A pointer to the object.
594 */
595 param_view const*
596 operator->() const noexcept
597 {
598 return this;
599 }
600
601 /** Aggregate construction
602
603 @param key_ The key to set.
604 @param value_ The value to set.
605 @param has_value_ True if a value is present.
606 */
607 1724 param_view(
608 core::string_view key_,
609 core::string_view value_,
610 bool has_value_) noexcept
611 1724 : key(key_)
612 1724 , value(has_value_
613
2/2
✓ Branch 0 taken 1357 times.
✓ Branch 1 taken 367 times.
1724 ? value_
614 : core::string_view())
615 1724 , has_value(has_value_)
616 {
617 1724 }
618
619 private:
620 173 param_view(
621 core::string_view key,
622 detail::optional_string const& value)
623 173 : param_view(key, value.s, value.b)
624 {
625 173 }
626 };
627
628 //------------------------------------------------
629
630 /** A view of a percent-encoded query parameter
631
632 Objects of this type represent a single key
633 and value pair in a query string where a key
634 is always present and may be empty, while the
635 presence of a value is indicated by
636 @ref has_value equal to true.
637 An empty value is distinct from no value.
638
639 The strings may have percent escapes, and
640 offer an additional invariant: they never
641 contain an invalid percent-encoding.
642
643 For most usages, key comparisons are
644 case-sensitive and duplicate keys in
645 a query are possible. However, it is
646 the authority that has final control
647 over how the query is interpreted.
648
649 <br>
650
651 Keys and values in this object reference
652 external character buffers.
653 Ownership of the buffers is not transferred;
654 the caller is responsible for ensuring that
655 the assigned buffers remain valid until
656 they are no longer referenced.
657
658 @par BNF
659 @code
660 query-params = query-param *( "&" query-param )
661 query-param = key [ "=" value ]
662 key = *qpchar
663 value = *( qpchar / "=" )
664 @endcode
665
666 @par Specification
667 @li <a href="https://en.wikipedia.org/wiki/Query_string"
668 >Query string (Wikipedia)</a>
669
670 @see
671 @ref param,
672 @ref param_view.
673 */
674 struct param_pct_view
675 {
676 /** The key
677
678 For most usages, key comparisons are
679 case-sensitive and duplicate keys in
680 a query are possible. However, it is
681 the authority that has final control
682 over how the query is interpreted.
683 */
684 pct_string_view key;
685
686 /** The value
687
688 The presence of a value is indicated by
689 @ref has_value equal to true.
690 An empty value is distinct from no value.
691 */
692 pct_string_view value;
693
694 /** True if a value is present
695
696 The presence of a value is indicated by
697 `has_value == true`.
698 An empty value is distinct from no value.
699 */
700 bool has_value = false;
701
702 //--------------------------------------------
703
704 /** Constructor
705
706 Default constructed query parameters
707 have an empty key and no value.
708
709 @par Example
710 @code
711 param_pct_view qp;
712 @endcode
713
714 @par Postconditions
715 @code
716 this->key == "" && this->value == "" && this->has_value == false
717 @endcode
718
719 @par Complexity
720 Constant.
721
722 @par Exception Safety
723 Throws nothing.
724 */
725 param_pct_view() = default;
726
727 /** Constructor
728
729 This constructs a parameter with a key
730 and value, which may both contain percent
731 escapes.
732 The new key and value reference
733 the same corresponding underlying
734 character buffers.
735 Ownership of the buffers is not transferred;
736 the caller is responsible for ensuring that
737 the assigned buffers remain valid until
738 they are no longer referenced.
739
740 @par Example
741 @code
742 param_pct_view qp( "key", "value" );
743 @endcode
744
745 @par Postconditions
746 @code
747 this->key.data() == key.data() && this->value.data() == value.data() && this->has_value == true
748 @endcode
749
750 @par Complexity
751 Linear in `key.size() + value.size()`.
752
753 @par Exception Safety
754 Exceptions thrown on invalid input.
755
756 @throw system_error
757 `key` or `value` contains an invalid percent-encoding.
758
759 @param key The key to set.
760 @param value The value to set.
761 */
762 1099 param_pct_view(
763 pct_string_view key,
764 pct_string_view value) noexcept
765 1099 : key(key)
766 1099 , value(value)
767 1099 , has_value(true)
768 {
769 1099 }
770
771 /** Constructor
772
773 This constructs a parameter with a key
774 and optional value, which may both
775 contain percent escapes.
776
777 The new key and value reference
778 the same corresponding underlying
779 character buffers.
780
781 Ownership of the buffers is not transferred;
782 the caller is responsible for ensuring that
783 the assigned buffers remain valid until
784 they are no longer referenced.
785
786 @par Example
787 @code
788 param_pct_view qp( "key", optional<core::string_view>("value") );
789 @endcode
790
791 @par Postconditions
792 @code
793 this->key.data() == key.data() && this->value->data() == value->data() && this->has_value == true
794 @endcode
795
796 @par Complexity
797 Linear in `key.size() + value->size()`.
798
799 @par Exception Safety
800 Exceptions thrown on invalid input.
801
802 @throw system_error
803 `key` or `value` contains an invalid percent-encoding.
804
805 @tparam OptionalString An optional
806 `core::string_view` type, such as
807 `boost::optional<core::string_view>` or
808 `std::optional<core::string_view>`.
809
810 @param key The key to set.
811 @param value The optional value to set.
812 @return A param object
813 */
814 template <class OptionalString>
815 974 param_pct_view(
816 pct_string_view key,
817 OptionalString const& value)
818
2/2
✓ Branch 2 taken 646 times.
✓ Branch 3 taken 3 times.
974 : param_pct_view(key, detail::get_optional_string(value))
819 {
820 968 }
821
822 /** Construction
823
824 This converts a param which may
825 contain unvalidated percent-escapes into
826 a param whose key and value are
827 guaranteed to contain strings with no
828 invalid percent-escapes, otherwise
829 an exception is thrown.
830
831 The new key and value reference
832 the same corresponding underlying
833 character buffers.
834 Ownership of the buffers is not transferred;
835 the caller is responsible for ensuring that
836 the assigned buffers remain valid until
837 they are no longer referenced.
838
839 @par Example
840 @code
841 param_pct_view qp( param_view( "key", "value" ) );
842 @endcode
843
844 @par Complexity
845 Linear in `key.size() + value.size()`.
846
847 @par Exception Safety
848 Exceptions thrown on invalid input.
849
850 @throw system_error
851 `key` or `value` contains an invalid percent escape.
852
853 @param p The param to construct from.
854 */
855 explicit
856 56 param_pct_view(
857 param_view const& p)
858 56 : key(p.key)
859 52 , value(p.has_value
860
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 9 times.
52 ? pct_string_view(p.value)
861 : pct_string_view())
862 51 , has_value(p.has_value)
863 {
864 51 }
865
866 /** Conversion
867
868 This function performs a conversion from
869 a reference-like query parameter to one
870 retaining ownership of the strings by
871 making a copy.
872
873 @par Complexity
874 Linear in `this->key.size() + this->value.size()`.
875
876 @par Exception Safety
877 Calls to allocate may throw.
878
879 @return A param object
880 */
881 explicit
882 2 operator
883 param() const
884 {
885 return param(
886 4 static_cast<std::string>(key),
887 6 static_cast<std::string>(value),
888 6 has_value);
889 }
890
891 /** Conversion to param_view
892
893 This function performs a conversion from
894 a pct_string_view query parameter to one
895 using a simple string_view.
896
897 @par Exception Safety
898 Calls to allocate may throw.
899
900 @return A param_view object
901 */
902 797 operator
903 param_view() const noexcept
904 {
905 return param_view(
906 797 key, value, has_value);
907 }
908
909 /** Arrow support
910
911 This operator returns the address of the
912 object so that it can be used in pointer
913 contexts.
914
915 @return A pointer to this object
916 */
917 param_pct_view const*
918 21 operator->() const noexcept
919 {
920 21 return this;
921 }
922
923 /** Aggregate construction
924
925 @param key The key
926 @param value The value
927 @param has_value True if a value is present
928 */
929 646 param_pct_view(
930 pct_string_view key,
931 pct_string_view value,
932 bool has_value) noexcept
933 646 : key(key)
934 646 , value(has_value
935
2/2
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 384 times.
646 ? value
936 : pct_string_view())
937 646 , has_value(has_value)
938 {
939 646 }
940
941 private:
942 649 param_pct_view(
943 pct_string_view key,
944 detail::optional_string const& value)
945
2/2
✓ Branch 1 taken 646 times.
✓ Branch 2 taken 3 times.
649 : param_pct_view(key, value.s, value.b)
946 {
947 646 }
948 };
949
950 //------------------------------------------------
951
952 inline
953 param&
954 1 param::
955 operator=(
956 param_view const& other)
957 {
958 // VFALCO operator= assignment
959 // causes a loss of original capacity:
960 // https://godbolt.org/z/nYef8445K
961 //
962 // key = other.key;
963 // value = other.value;
964
965 // preserve capacity
966 1 key.assign(
967 other.key.data(),
968 other.key.size());
969 1 value.assign(
970 other.value.data(),
971 other.value.size());
972 1 has_value = other.has_value;
973 1 return *this;
974 }
975
976 inline
977 param&
978 1 param::
979 operator=(
980 param_pct_view const& other)
981 {
982 // preserve capacity
983 1 key.assign(
984 other.key.data(),
985 other.key.size());
986 1 value.assign(
987 other.value.data(),
988 other.value.size());
989 1 has_value = other.has_value;
990 1 return *this;
991 }
992
993 } // urls
994 } // boost
995
996 #endif
997