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