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_SEGMENTS_ENCODED_REF_HPP
12 : #define BOOST_URL_SEGMENTS_ENCODED_REF_HPP
13 :
14 : #include <boost/url/detail/config.hpp>
15 : #include <boost/url/segments_encoded_base.hpp>
16 : #include <initializer_list>
17 : #include <iterator>
18 :
19 : namespace boost {
20 : namespace urls {
21 :
22 : #ifndef BOOST_URL_DOCS
23 : class url_base;
24 : class segments_encoded_view;
25 : #endif
26 :
27 : /** Mutable encoded path segment proxy
28 :
29 : Exposes the percent-encoded segments of a
30 : @ref url_base as a bidirectional range that
31 : can modify the underlying URL. The proxy uses
32 : the URL’s storage directly, so the url must
33 : outlive any references.
34 :
35 : @par Example
36 : @code
37 : url u( "/path/to/file.txt" );
38 :
39 : segments_encoded_ref ps = u.encoded_segments();
40 : @endcode
41 :
42 : The strings returned when iterators are
43 : dereferenced have type @ref pct_string_view
44 : and may contain percent-escapes.
45 :
46 : Reserved characters in inputs are
47 : automatically escaped.
48 : Escapes in inputs are preserved.
49 :
50 : Exceptions are thrown on invalid inputs.
51 :
52 : @par Iterator Invalidation
53 : Changes to the underlying character buffer
54 : can invalidate iterators which reference it.
55 : Modifications made through the container
56 : invalidate some or all iterators:
57 : <br>
58 :
59 : @li @ref push_back : Only `end()`.
60 :
61 : @li @ref assign, @ref clear,
62 : @ref operator= : All elements.
63 :
64 : @li @ref erase : Erased elements and all
65 : elements after (including `end()`).
66 :
67 : @li @ref insert : All elements at or after
68 : the insertion point (including `end()`).
69 :
70 : @li @ref replace : Modified
71 : elements and all elements
72 : after (including `end()`).
73 :
74 : @see
75 : @ref segments_encoded_view,
76 : @ref segments_view,
77 : @ref segments_ref.
78 : */
79 : class BOOST_URL_DECL segments_encoded_ref
80 : : public segments_encoded_base
81 : {
82 : friend class url_base;
83 :
84 : url_base* u_ = nullptr;
85 :
86 : segments_encoded_ref(
87 : url_base& u) noexcept;
88 :
89 : public:
90 : //--------------------------------------------
91 : //
92 : // Special Members
93 : //
94 : //--------------------------------------------
95 :
96 : /** Constructor
97 :
98 : After construction, both views
99 : reference the same url. Ownership is not
100 : transferred; the caller is responsible
101 : for ensuring the lifetime of the url
102 : extends until it is no longer
103 : referenced.
104 :
105 : @par Postconditions
106 : @code
107 : &this->url() == &other.url();
108 : @endcode
109 :
110 : @par Complexity
111 : Constant.
112 :
113 : @par Exception Safety
114 : Throws nothing.
115 :
116 : @param other The other view.
117 : */
118 : segments_encoded_ref(
119 : segments_encoded_ref const& other) = default;
120 :
121 : /** Assignment
122 :
123 : The existing contents are replaced
124 : by a copy of the other segments.
125 :
126 : <br>
127 : All iterators are invalidated.
128 :
129 : @note
130 : None of the character buffers referenced
131 : by `other` may overlap the buffer of the
132 : underlying url, or else the behavior
133 : is undefined.
134 :
135 : @par Effects
136 : @code
137 : this->assign( other.begin(), other.end() );
138 : @endcode
139 :
140 : @par Complexity
141 : Linear in `other.buffer().size()`.
142 :
143 : @par Exception Safety
144 : Strong guarantee.
145 : Calls to allocate may throw.
146 :
147 : @param other The segments to assign.
148 : @return A reference to this object.
149 : */
150 : segments_encoded_ref&
151 : operator=(segments_encoded_ref const& other);
152 :
153 : /// @copydoc operator=(segments_encoded_ref const&)
154 : segments_encoded_ref&
155 : operator=(segments_encoded_view const& other);
156 :
157 : /** Assignment
158 :
159 : The existing contents are replaced
160 : by a copy of the contents of the
161 : initializer list.
162 : Reserved characters in the list are
163 : automatically escaped.
164 : Escapes in the list are preserved.
165 :
166 : <br>
167 : All iterators are invalidated.
168 :
169 : @par Example
170 : @code
171 : url u;
172 :
173 : u.encoded_segments() = {"path", "to", "file.txt"};
174 : @endcode
175 :
176 : @par Preconditions
177 : None of the character buffers referenced
178 : by the list may overlap the character buffer
179 : of the underlying url, or else the behavior
180 : is undefined.
181 :
182 : @par Effects
183 : @code
184 : this->assign( init.begin(), init.end() );
185 : @endcode
186 :
187 : @par Complexity
188 : Linear in `init.size() + this->url().encoded_query().size() + this->url().encoded_fragment().size()`.
189 :
190 : @par Exception Safety
191 : Strong guarantee.
192 : Calls to allocate may throw.
193 : Exceptions thrown on invalid input.
194 :
195 : @throw system_error
196 : The list contains an invalid percent-encoding.
197 :
198 : @param init The list of segments to assign.
199 : @return A reference to this.
200 : */
201 : segments_encoded_ref&
202 : operator=(std::initializer_list<
203 : pct_string_view> init);
204 :
205 : /** Conversion
206 :
207 : @see
208 : @ref segments_encoded_view.
209 :
210 : @return A view of the segments.
211 : */
212 : operator
213 : segments_encoded_view() const noexcept;
214 :
215 : //--------------------------------------------
216 : //
217 : // Observers
218 : //
219 : //--------------------------------------------
220 :
221 : /** Return the referenced url
222 :
223 : This function returns the url referenced
224 : by the view.
225 :
226 : @par Example
227 : @code
228 : url u( "/path/to/file.txt" );
229 :
230 : assert( &u.encoded_segments().url() == &u );
231 : @endcode
232 :
233 : @par Exception Safety
234 : Throws nothing.
235 :
236 : @return A reference to the url.
237 : */
238 : url_base&
239 9 : url() const noexcept
240 : {
241 9 : return *u_;
242 : }
243 :
244 : //--------------------------------------------
245 : //
246 : // Modifiers
247 : //
248 : //--------------------------------------------
249 :
250 : /** Clear the contents of the container
251 :
252 : <br>
253 : All iterators are invalidated.
254 :
255 : @par Effects
256 : @code
257 : this->url().set_encoded_path( "" );
258 : @endcode
259 :
260 : @par Postconditions
261 : @code
262 : this->empty() == true
263 : @endcode
264 :
265 : @par Complexity
266 : Linear in `this->url().encoded_query().size() + this->url().encoded_fragment().size()`.
267 :
268 : @par Exception Safety
269 : Throws nothing.
270 : */
271 : void
272 : clear() noexcept;
273 :
274 : /** Assign segments
275 :
276 : The existing contents are replaced
277 : by a copy of the contents of the
278 : initializer list.
279 : Reserved characters in the list are
280 : automatically escaped.
281 : Escapes in the list are preserved.
282 :
283 : <br>
284 : All iterators are invalidated.
285 :
286 : @note
287 : None of the character buffers referenced
288 : by the list may overlap the character
289 : buffer of the underlying url, or else
290 : the behavior is undefined.
291 :
292 : @par Example
293 : @code
294 : url u;
295 :
296 : u.segments().assign( {"path", "to", "file.txt"} );
297 : @endcode
298 :
299 : @par Complexity
300 : Linear in `init.size() + this->url().encoded_query().size() + this->url().encoded_fragment().size()`.
301 :
302 : @par Exception Safety
303 : Strong guarantee.
304 : Calls to allocate may throw.
305 : Exceptions thrown on invalid input.
306 :
307 : @throw system_error
308 : The list contains an invalid percent-encoding.
309 :
310 : @param init The list of segments to assign.
311 : */
312 : void
313 : assign(std::initializer_list<
314 : pct_string_view> init);
315 :
316 : /** Assign segments
317 :
318 : The existing contents are replaced
319 : by a copy of the contents of the range.
320 : Reserved characters in the range are
321 : automatically escaped.
322 : Escapes in the range are preserved.
323 :
324 : <br>
325 : All iterators are invalidated.
326 :
327 : @note
328 : None of the character buffers referenced
329 : by the range may overlap the character
330 : buffer of the underlying url, or else
331 : the behavior is undefined.
332 :
333 : @par Mandates
334 : @code
335 : std::is_convertible< std::iterator_traits< FwdIt >::reference_type, pct_string_view >::value == true
336 : @endcode
337 :
338 : @par Complexity
339 : Linear in `std::distance( first, last ) + this->url().encoded_query().size() + this->url().encoded_fragment().size()`.
340 :
341 : @par Exception Safety
342 : Strong guarantee.
343 : Calls to allocate may throw.
344 : Exceptions thrown on invalid input.
345 :
346 : @throw system_error
347 : The range contains an invalid percent-encoding.
348 :
349 : @param first The first element in the range.
350 : @param last One past the last element in the range.
351 : */
352 : template<class FwdIt>
353 : void
354 : assign(FwdIt first, FwdIt last);
355 :
356 : //--------------------------------------------
357 :
358 : /** Insert segments
359 :
360 : This function inserts a segment
361 : before the specified position.
362 : Reserved characters in the segment are
363 : automatically escaped.
364 : Escapes in the segment are preserved.
365 :
366 : <br>
367 : All iterators that are equal to
368 : `before` or come after are invalidated.
369 :
370 : @par Complexity
371 : Linear in `s.size() + this->url().encoded_resource().size()`.
372 :
373 : @par Exception Safety
374 : Strong guarantee.
375 : Calls to allocate may throw.
376 : Exceptions thrown on invalid input.
377 :
378 : @throw system_error
379 : The segment contains an invalid percent-encoding.
380 :
381 : @return An iterator to the inserted
382 : segment.
383 :
384 : @param before An iterator before which
385 : the segment is inserted. This may
386 : be equal to `end()`.
387 :
388 : @param s The segment to insert.
389 : */
390 : iterator
391 : insert(
392 : iterator before,
393 : pct_string_view s);
394 :
395 : /** Insert segments
396 :
397 : This function inserts the segments
398 : in an initializer list before the
399 : specified position.
400 : Reserved characters in the list are
401 : automatically escaped.
402 : Escapes in the list are preserved.
403 :
404 : <br>
405 : All iterators that are equal to
406 : `before` or come after are invalidated.
407 :
408 : @note
409 : None of the character buffers referenced
410 : by the list may overlap the character
411 : buffer of the underlying url, or else
412 : the behavior is undefined.
413 :
414 : @par Example
415 : @code
416 : url u( "/file.txt" );
417 :
418 : u.encoded_segments().insert( u.encoded_segments().begin(), { "path", "to" } );
419 : @endcode
420 :
421 : @par Complexity
422 : Linear in `init.size() + this->url().encoded_resource().size()`.
423 :
424 : @par Exception Safety
425 : Strong guarantee.
426 : Calls to allocate may throw.
427 : Exceptions thrown on invalid input.
428 :
429 : @throw system_error
430 : The list contains an invalid percent-encoding.
431 :
432 : @return An iterator to the first
433 : element inserted, or `before` if
434 : `init.size() == 0`.
435 :
436 : @param before An iterator before which
437 : the list is inserted. This may
438 : be equal to `end()`.
439 :
440 : @param init The list of segments to insert.
441 : */
442 : iterator
443 : insert(
444 : iterator before,
445 : std::initializer_list<
446 : pct_string_view> init);
447 :
448 : /** Insert segments
449 :
450 : This function inserts the segments in
451 : a range before the specified position.
452 : Reserved characters in the range are
453 : automatically escaped.
454 : Escapes in the range are preserved.
455 :
456 : <br>
457 : All iterators that are equal to
458 : `before` or come after are invalidated.
459 :
460 : @note
461 : None of the character buffers referenced
462 : by the range may overlap the character
463 : buffer of the underlying url, or else
464 : the behavior is undefined.
465 :
466 : @par Mandates
467 : @code
468 : std::is_convertible< std::iterator_traits< FwdIt >::reference_type, pct_string_view >::value == true
469 : @endcode
470 :
471 : @par Complexity
472 : Linear in `std::distance( first, last ) + this->url().encoded_resource().size()`.
473 :
474 : @par Exception Safety
475 : Strong guarantee.
476 : Calls to allocate may throw.
477 : Exceptions thrown on invalid input.
478 :
479 : @throw system_error
480 : The range contains an invalid percent-encoding.
481 :
482 : @return An iterator to the first
483 : segment inserted, or `before` if
484 : `init.empty()`.
485 :
486 : @param before An iterator before which
487 : the range is inserted. This may
488 : be equal to `end()`.
489 :
490 : @param first The first element in the range to insert.
491 : @param last One past the last element in the range to insert.
492 : */
493 : template<class FwdIt>
494 : iterator
495 : insert(
496 : iterator before,
497 : FwdIt first,
498 : FwdIt last);
499 :
500 : //--------------------------------------------
501 :
502 : /** Erase segments
503 :
504 : This function removes a segment.
505 :
506 : <br>
507 : All iterators that are equal to
508 : `pos` or come after are invalidated.
509 :
510 : @par Complexity
511 : Linear in `this->url().encoded_resource().size()`.
512 :
513 : @par Exception Safety
514 : Throws nothing.
515 :
516 : @return An iterator to one past
517 : the removed segment.
518 :
519 : @param pos An iterator to the element.
520 : */
521 : iterator
522 : erase(
523 : iterator pos) noexcept;
524 :
525 : /** Erase segments
526 :
527 : This function removes a range of segments
528 : from the container.
529 :
530 : <br>
531 : All iterators that are equal to
532 : `first` or come after are invalidated.
533 :
534 : @par Complexity
535 : Linear in `this->url().encoded_resource().size()`.
536 :
537 : @par Exception Safety
538 : Throws nothing.
539 :
540 : @param first The first element in the range to erase.
541 : @param last One past the last element in the range to erase.
542 : @return An iterator to one past the removed range.
543 : */
544 : iterator
545 : erase(
546 : iterator first,
547 : iterator last) noexcept;
548 :
549 : //--------------------------------------------
550 :
551 : /** Replace segments
552 :
553 : This function replaces the segment at
554 : the specified position.
555 : Reserved characters in the string are
556 : automatically escaped.
557 : Escapes in the string are preserved.
558 :
559 : <br>
560 : All iterators that are equal to
561 : `pos` or come after are invalidated.
562 :
563 : @par Complexity
564 : Linear in `s.size() + this->url().encoded_resouce().size()`.
565 :
566 : @par Exception Safety
567 : Strong guarantee.
568 : Calls to allocate may throw.
569 :
570 : @return An iterator to the replaced segment.
571 :
572 : @param pos An iterator to the segment.
573 :
574 : @param s The string to assign.
575 : */
576 : iterator
577 : replace(
578 : iterator pos,
579 : pct_string_view s);
580 :
581 : /** Replace segments
582 :
583 : This function replaces a range of
584 : segments with one segment.
585 : Reserved characters in the string are
586 : automatically escaped.
587 : Escapes in the string are preserved.
588 :
589 : <br>
590 : All iterators that are equal to
591 : `from` or come after are invalidated.
592 :
593 : @par Complexity
594 : Linear in `s.size() + this->url().encoded_resouce().size()`.
595 :
596 : @par Exception Safety
597 : Strong guarantee.
598 : Calls to allocate may throw.
599 : Exceptions thrown on invalid input.
600 :
601 : @throw system_error
602 : The string contains an invalid percent-encoding.
603 :
604 : @return An iterator to the new segment.
605 :
606 : @param from The first element in the range of segments to replace.
607 : @param to One past the last element in the range of segments to replace.
608 :
609 : @param s The string to assign.
610 : */
611 : iterator
612 : replace(
613 : iterator from,
614 : iterator to,
615 : pct_string_view s);
616 :
617 : /** Replace segments
618 :
619 : This function replaces a range of
620 : segments with a list of segments in
621 : an initializer list.
622 : Reserved characters in the list are
623 : automatically escaped.
624 : Escapes in the list are preserved.
625 :
626 : <br>
627 : All iterators that are equal to
628 : `from` or come after are invalidated.
629 :
630 : @par Preconditions
631 : None of the character buffers referenced
632 : by the list may overlap the character
633 : buffer of the underlying url, or else
634 : the behavior is undefined.
635 :
636 : @par Complexity
637 : Linear in `init.size() + this->url().encoded_resouce().size()`.
638 :
639 : @par Exception Safety
640 : Strong guarantee.
641 : Calls to allocate may throw.
642 : Exceptions thrown on invalid input.
643 :
644 : @throw system_error
645 : The list contains an invalid percent-encoding.
646 :
647 : @return An iterator to the first
648 : segment inserted, or one past `to` if
649 : `init.size() == 0`.
650 :
651 : @param from The first element in the range of segments to replace.
652 : @param to One past the last element in the range of segments to replace.
653 :
654 : @param init The list of segments to assign.
655 : */
656 : iterator
657 : replace(
658 : iterator from,
659 : iterator to,
660 : std::initializer_list<
661 : pct_string_view> init);
662 :
663 : /** Replace segments
664 :
665 : This function replaces a range of
666 : segments with annother range of segments.
667 : Reserved characters in the new range are
668 : automatically escaped.
669 : Escapes in the new range are preserved.
670 :
671 : <br>
672 : All iterators that are equal to
673 : `from` or come after are invalidated.
674 :
675 : @par Preconditions
676 : None of the character buffers referenced
677 : by the new range may overlap the character
678 : buffer of the underlying url, or else
679 : the behavior is undefined.
680 :
681 : @par Complexity
682 : Linear in `std::distance( first, last ) + this->url().encoded_resouce().size()`.
683 :
684 : @par Exception Safety
685 : Strong guarantee.
686 : Calls to allocate may throw.
687 : Exceptions thrown on invalid input.
688 :
689 : @throw system_error
690 : The range contains an invalid percent-encoding.
691 :
692 : @return An iterator to the first
693 : segment inserted, or one past `to` if
694 : `init.size() == 0`.
695 :
696 : @param from The first element in the range of segments to replace.
697 : @param to One past the last element in the range of segments to replace.
698 : @param first The first element in the new range of segments.
699 : @param last One past the last element in the new range of segments.
700 : */
701 : template<class FwdIt>
702 : iterator
703 : replace(
704 : iterator from,
705 : iterator to,
706 : FwdIt first,
707 : FwdIt last);
708 :
709 : //--------------------------------------------
710 :
711 : /** Append a segment
712 :
713 : This function appends a segment to
714 : the end of the path.
715 : Reserved characters in the string are
716 : automatically escaped.
717 : Escapes in the string are preserved.
718 :
719 : <br>
720 : All end iterators are invalidated.
721 :
722 : @par Postconditions
723 : @code
724 : this->back() == s
725 : @endcode
726 :
727 : @par Exception Safety
728 : Strong guarantee.
729 : Calls to allocate may throw.
730 : Exceptions thrown on invalid input.
731 :
732 : @throw system_error
733 : The string contains an invalid percent-encoding.
734 :
735 : @param s The segment to append.
736 : */
737 : void
738 : push_back(
739 : pct_string_view s);
740 :
741 : /** Remove the last segment
742 :
743 : This function removes the last segment
744 : from the container.
745 :
746 : <br>
747 : Iterators to the last segment as well
748 : as all end iterators are invalidated.
749 :
750 : @par Preconditions
751 : @code
752 : !this->empty()
753 : @endcode
754 :
755 : @par Exception Safety
756 : Throws nothing.
757 : */
758 : void
759 : pop_back() noexcept;
760 :
761 : private:
762 : template<class FwdIt>
763 : iterator
764 : insert(
765 : iterator before,
766 : FwdIt first,
767 : FwdIt last,
768 : std::input_iterator_tag) = delete;
769 :
770 : template<class FwdIt>
771 : iterator
772 : insert(
773 : iterator before,
774 : FwdIt first,
775 : FwdIt last,
776 : std::forward_iterator_tag);
777 : };
778 :
779 : } // urls
780 : } // boost
781 :
782 : // This is in <boost/url/url_base.hpp>
783 : //
784 : // #include <boost/url/impl/segments_encoded_ref.hpp>
785 :
786 : //------------------------------------------------
787 : //
788 : // std::ranges::enable_borrowed_range
789 : //
790 : //------------------------------------------------
791 :
792 : #ifdef BOOST_URL_HAS_CONCEPTS
793 : #include <ranges>
794 : namespace std::ranges {
795 : template<>
796 : inline constexpr bool
797 : enable_borrowed_range<
798 : boost::urls::segments_encoded_ref> = true;
799 : } // std::ranges
800 : #endif
801 :
802 : #endif
|