HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
URI.hpp
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
9#pragma once
10
11#include "../utility/utility.hpp"
12#include "../algorithm/module.hpp"
13#include "../macros.hpp"
14#include <string>
15#include <optional>
16#include <ranges>
17
18hi_export_module(hikogui.path.URI);
19
20namespace hi { inline namespace v1 {
21
22#define HI_SUB_DELIM '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '='
23#define HI_PCHAR HI_SUB_DELIM, ':', '@'
24
39class URI {
40private:
41 using const_iterator = std::string_view::const_iterator;
42
43public:
45 public:
46 constexpr authority_type() noexcept = default;
47 constexpr authority_type(authority_type const&) noexcept = default;
48 constexpr authority_type(authority_type&&) noexcept = default;
49 constexpr authority_type& operator=(authority_type const&) noexcept = default;
50 constexpr authority_type& operator=(authority_type&&) noexcept = default;
51
52 constexpr authority_type(std::string_view const& rhs) noexcept
53 {
54 parse(rhs);
55 }
56
57 // constexpr void normalize(std::optional<std::string> const& scheme) noexcept
58 //{
59 // hi_not_implemented();
60 // }
61
62 [[nodiscard]] constexpr std::optional<std::string> const& userinfo() const noexcept
63 {
64 return _userinfo;
65 }
66
67 constexpr authority_type& set_userinfo(std::optional<std::string> const& rhs) noexcept
68 {
69 _userinfo = rhs;
70 return *this;
71 }
72
73 [[nodiscard]] constexpr std::string const& host() const noexcept
74 {
75 return _host;
76 }
77
78 constexpr authority_type& set_host(std::string const& rhs)
79 {
80 validate_host(rhs);
81 _host = to_lower(rhs);
82 return *this;
83 }
84
85 [[nodiscard]] constexpr std::optional<std::string> const& port() const noexcept
86 {
87 return _port;
88 }
89
90 constexpr authority_type& set_port(std::optional<std::string> const& rhs)
91 {
92 if (rhs) {
93 validate_port(*rhs);
94 _port = *rhs;
95 } else {
96 _port = {};
97 }
98 return *this;
99 }
100
101 [[nodiscard]] constexpr friend bool operator==(authority_type const&, authority_type const&) noexcept = default;
102 [[nodiscard]] constexpr friend auto operator<=>(authority_type const&, authority_type const&) noexcept = default;
103
104 [[nodiscard]] constexpr friend size_t to_string_size(authority_type const& rhs) noexcept
105 {
106 auto size = 0_uz;
107 if (rhs._userinfo) {
108 size += rhs._userinfo->size() + 1;
109 }
110 size += rhs._host.size();
111 if (rhs._port) {
112 size += rhs._port->size() + 1;
113 }
114 return size;
115 }
116
117 [[nodiscard]] constexpr friend std::string to_string(authority_type const& rhs) noexcept
118 {
119 auto r = std::string{};
120
121 if (rhs._userinfo) {
122 r += URI::encode<HI_SUB_DELIM, ':'>(*rhs._userinfo);
123 r += '@';
124 }
125
126 if (rhs._host.empty() or rhs._host.front() != '[') {
127 r += URI::encode<HI_SUB_DELIM>(rhs._host);
128 } else {
129 r += URI::encode<HI_SUB_DELIM, '[', ']', ':'>(rhs._host);
130 }
131
132 if (rhs._port) {
133 r += ':';
134 r += *rhs._port;
135 }
136
137 return r;
138 }
139
140 private:
141 std::optional<std::string> _userinfo = {};
142 std::string _host = {};
143 std::optional<std::string> _port = {};
144
145 [[nodiscard]] constexpr static void validate_host(std::string_view str)
146 {
147 if (str.starts_with('[') and not str.ends_with(']')) {
148 throw uri_error("The host-component starts with '[' has missing ']' at end");
149 } else if (str.ends_with(']') and str.starts_with('[')) {
150 throw uri_error("The host-component ends with ']' has missing '[' at start");
151 }
152 }
153
154 [[nodiscard]] constexpr static void validate_port(std::string_view str)
155 {
156 for (auto c : str) {
157 if (not(c >= '0' and c <= '9')) {
158 throw uri_error("The port-component contains a non-digit.");
159 }
160 }
161 }
162
170 [[nodiscard]] constexpr const_iterator parse_userinfo(const_iterator first, const_iterator last) noexcept
171 {
172 for (auto it = first; it != last; ++it) {
173 if (hilet c = *it; c == '@') {
174 set_userinfo(URI::decode(first, it));
175 return it + 1; // Skip over '@'.
176 }
177 }
178
179 // Reached at end of URI, this is not a userinfo.
180 return first;
181 }
182
189 [[nodiscard]] constexpr const_iterator parse_host(const_iterator first, const_iterator last) noexcept
190 {
191 if (first == last) {
192 return first;
193 }
194
195 auto it = first;
196 if (*it == '[') {
197 while (it != last) {
198 if (*it == ']') {
199 set_host(URI::decode(first, it + 1));
200 return it + 1; // Skip over ']'.
201 }
202 }
203 // End of URI mean this is not a host, interpret as path instead.
204 return first;
205
206 } else {
207 for (; it != last; ++it) {
208 if (hilet c = *it; c == ':') {
209 // End of host.
210 set_host(URI::decode(first, it));
211 return it;
212 }
213 }
214
215 // End of URI means that the host is the last part of the URI
216 set_host(URI::decode(first, last));
217 return last;
218 }
219 }
220
221 [[nodiscard]] constexpr const_iterator parse_port(const_iterator first, const_iterator last) noexcept
222 {
223 set_port(std::string{first, last});
224 return last;
225 }
226
227 constexpr void parse(std::string_view rhs) noexcept
228 {
229 auto first = rhs.cbegin();
230 auto last = rhs.cend();
231 auto it = parse_userinfo(first, last);
232 it = parse_host(it, last);
233
234 if (it != last and *it == ':') {
235 it = parse_port(++it, last);
236 }
237 }
238 };
239
270 class path_type : public std::vector<std::string> {
271 public:
272 constexpr path_type() noexcept = default;
273 constexpr path_type(path_type const&) noexcept = default;
274 constexpr path_type(path_type&&) noexcept = default;
275 constexpr path_type& operator=(path_type const&) noexcept = default;
276 constexpr path_type& operator=(path_type&&) noexcept = default;
277
278 [[nodiscard]] constexpr static std::vector<std::string> parse(std::string_view str)
279 {
280 auto r = make_vector<std::string>(std::views::transform(std::views::split(str, std::string_view{"/"}), [](auto&& x) {
281 return URI::decode(std::string_view{std::ranges::begin(x), std::ranges::end(x)});
282 }));
283
284 if (r.size() == 1 and r.front().empty()) {
285 // An empty string will evaluate to a single segment.
286 r.clear();
287 }
288 if (not r.empty() and (r.back() == "." or r.back() == ".." or r.back() == "**")) {
289 // ".", ".." and "**" are directories always terminate with a slash.
290 r.emplace_back();
291 }
292
293 return r;
294 }
295
296 constexpr path_type(std::string_view str) noexcept : std::vector<std::string>(parse(str))
297 {
298 hi_axiom(holds_invariant());
299 }
300
301 [[nodiscard]] constexpr bool absolute() const noexcept
302 {
303 return size() >= 2 and front().empty();
304 }
305
306 [[nodiscard]] constexpr bool double_absolute() const noexcept
307 {
308 return size() >= 3 and (*this)[0].empty() and (*this)[1].empty();
309 }
310
311 [[nodiscard]] constexpr bool is_root() const noexcept
312 {
313 return size() == 2 and (*this)[0].empty() and (*this)[1].empty();
314 }
315
316 [[nodiscard]] constexpr std::optional<std::string> filename() const noexcept
317 {
318 if (empty() or back().empty()) {
319 return {};
320 } else {
321 return back();
322 }
323 }
324
331 {
332 switch (size()) {
333 case 0: // Don't remove a filename from an empty path.
334 break;
335 case 1: // relative filename, make the path empty.
336 clear();
337 break;
338 default: // relative or absolute directory with optional filename. Just empty the last path segment.
339 back().clear();
340 }
341 hi_axiom(holds_invariant());
342 return *this;
343 }
344
345 [[nodiscard]] constexpr friend path_type merge(path_type base, path_type const& ref, bool base_has_authority) noexcept
346 {
347 if (base_has_authority and base.empty()) {
348 // A URL with an authority and empty path is implicitly the root path.
349 base.emplace_back();
350 base.emplace_back();
351 }
352
353 if (not base.empty()) {
354 // Remove the (possibly empty) filename from the base.
355 base.pop_back();
356 }
357 base.insert(base.cend(), ref.cbegin(), ref.cend());
358
359 if (base.size() == 1 and base.front().empty()) {
360 // Empty ref-path added to root base-path, fix by appending an empty filename.
361 base.emplace_back();
362 }
363
364 hi_axiom(base.holds_invariant());
365 return base;
366 }
367
393 [[nodiscard]] constexpr friend path_type remove_dot_segments(path_type path) noexcept
394 {
395 for (auto it = path.cbegin(); it != path.cend();) {
396 if (*it == ".") {
397 // Remove any "." from the path.
398 it = path.erase(it);
399
400 } else if (*it == "..") {
401 if (it == path.cbegin()) {
402 // Remove the ".." at the start of a relative path.
403 it = path.erase(it);
404
405 } else if (it - 1 == path.cbegin() and (it - 1)->empty()) {
406 // Remove just the ".." at the start of an absolute path.
407 it = path.erase(it);
408
409 } else {
410 // Remove ".." and the segment in front of it.
411 it = path.erase(it - 1, it + 1);
412 }
413 } else {
414 // Ignore other segments.
415 ++it;
416 }
417 }
418
419 if (path.size() == 1 and path.front().empty()) {
420 // After removing the ".." at the start of the path we are left with an empty segment.
421 path.clear();
422 }
423
424 hi_axiom(path.holds_invariant());
425 return path;
426 }
427
428 [[nodiscard]] constexpr bool holds_invariant() const noexcept
429 {
430 if (empty()) {
431 return true;
432 }
433
434 if (back() == "." or back() == ".." or back() == "**") {
435 // ".", ".." and "**" are always directories and may not be the last segment.
436 return false;
437 }
438 return true;
439 }
440
441 [[nodiscard]] constexpr friend size_t to_string_size(path_type const& rhs) noexcept
442 {
443 size_t r = 0_uz;
444 for (hilet& segment : rhs) {
445 r += segment.size();
446 }
447 r += rhs.size() + 1;
448 return r;
449 }
450
457 [[nodiscard]] constexpr friend std::string to_string(path_type const& rhs, bool has_scheme = false) noexcept
458 {
459 auto r = std::string{};
460 r.reserve(to_string_size(rhs));
461
462 auto segment_is_empty = false;
463 for (auto it = rhs.cbegin(); it != rhs.cend(); ++it) {
464 segment_is_empty = it->empty();
465
466 if (it == rhs.cbegin() and not has_scheme) {
467 r += URI::encode<HI_SUB_DELIM, '@'>(*it);
468 } else {
469 r += URI::encode<HI_PCHAR>(*it);
470 }
471 r += '/';
472 }
473
474 if (not r.empty() and not segment_is_empty) {
475 // The last path-component was a filename, remove the trailing slash '/'.
476 r.pop_back();
477 }
478 return r;
479 }
480 };
481
482 constexpr URI() noexcept = default;
487
494 constexpr explicit URI(std::string_view str)
495 {
496 parse(str);
497 }
498
505 constexpr explicit URI(std::string const& str) : URI(std::string_view{str}) {}
506
513 constexpr explicit URI(const char *str) : URI(std::string_view{str}) {}
514
515 [[nodiscard]] constexpr bool empty() const noexcept
516 {
517 return not _scheme and not _authority and _path.empty() and not _query and not _fragment;
518 }
519
520 constexpr operator bool() const noexcept
521 {
522 return not empty();
523 }
524
529 [[nodiscard]] constexpr std::optional<std::string> const& scheme() const noexcept
530 {
531 return _scheme;
532 }
533
537 constexpr URI& set_scheme(std::optional<std::string> const& rhs)
538 {
539 if (rhs) {
540 validate_scheme(*rhs);
541 _scheme = *rhs;
542 } else {
543 _scheme = {};
544 }
545 return *this;
546 }
547
552 [[nodiscard]] constexpr std::optional<authority_type> const& authority() const noexcept
553 {
554 return _authority;
555 }
556
557 constexpr URI& set_authority(std::optional<authority_type> const& rhs) noexcept
558 {
559 _authority = rhs;
560 return *this;
561 }
562
563 [[nodiscard]] constexpr path_type const& path() const noexcept
564 {
565 return _path;
566 }
567
568 constexpr URI& set_path(path_type const& rhs)
569 {
570 validate_path(rhs, to_bool(_authority));
571 _path = rhs;
572 return *this;
573 }
574
575 [[nodiscard]] constexpr std::optional<std::string> filename() const noexcept
576 {
577 return _path.filename();
578 }
579
586 {
587 _path.remove_filename();
588 return *this;
589 }
590
595 [[nodiscard]] constexpr std::optional<std::string> const& query() const noexcept
596 {
597 return _query;
598 }
599
600 constexpr URI& set_query(std::optional<std::string> const& rhs) noexcept
601 {
602 _query = rhs;
603 return *this;
604 }
605
610 [[nodiscard]] constexpr std::optional<std::string> const& fragment() const noexcept
611 {
612 return _fragment;
613 }
614
615 constexpr URI& set_fragment(std::optional<std::string> const& rhs) noexcept
616 {
617 _fragment = rhs;
618 return *this;
619 }
620
621 [[nodiscard]] constexpr friend std::string to_string(URI const& rhs) noexcept
622 {
623 auto r = std::string{};
624 r.reserve(to_string_size(rhs));
625
626 if (rhs._scheme) {
627 r += *rhs._scheme;
628 r += ':';
629 }
630
631 if (rhs._authority) {
632 r += '/';
633 r += '/';
634 r += to_string(*rhs._authority);
635 }
636
637 r += to_string(rhs._path, to_bool(rhs._scheme));
638
639 if (rhs._query) {
640 r += '?';
641 r += URI::encode<HI_PCHAR, '/', '?'>(*rhs._query);
642 }
643
644 if (rhs._fragment) {
645 r += '#';
646 r += URI::encode<HI_PCHAR, '/', '?'>(*rhs._fragment);
647 }
648
649 return r;
650 }
651
652 friend std::ostream& operator<<(std::ostream& lhs, URI const& rhs) noexcept
653 {
654 return lhs << to_string(rhs);
655 }
656
657 [[nodiscard]] constexpr friend bool operator==(URI const& lhs, URI const& rhs) noexcept = default;
658 [[nodiscard]] constexpr friend auto operator<=>(URI const& lhs, URI const& rhs) noexcept = default;
659
660 [[nodiscard]] constexpr friend URI operator/(URI const& base, URI const& ref) noexcept
661 {
662 auto target = URI{};
663
664 if (ref._scheme) {
665 target._scheme = ref._scheme;
666 target._authority = ref._authority;
667 target._path = remove_dot_segments(ref._path);
668 target._query = ref._query;
669 } else {
670 if (ref._authority) {
671 target._authority = ref._authority;
672 target._path = remove_dot_segments(ref._path);
673 target._query = ref._query;
674
675 } else {
676 if (ref._path.empty()) {
677 target._path = base._path;
678 if (ref._query) {
679 target._query = ref._query;
680 } else {
681 target._query = base._query;
682 }
683 } else {
684 if (ref._path.absolute()) {
685 target._path = remove_dot_segments(ref._path);
686 } else {
687 target._path = remove_dot_segments(merge(base._path, ref._path, to_bool(base._authority)));
688 }
689 target._query = ref._query;
690 }
691 target._authority = base._authority;
692 }
693 target._scheme = base._scheme;
694 }
695
696 target._fragment = ref._fragment;
697
698 return target;
699 }
700
701 [[nodiscard]] constexpr friend bool operator==(URI const& lhs, std::string_view rhs) noexcept
702 {
703 return lhs == URI(rhs);
704 }
705
706 [[nodiscard]] constexpr friend auto operator<=>(URI const& lhs, std::string_view rhs) noexcept
707 {
708 return lhs == URI(rhs);
709 }
710
711 [[nodiscard]] constexpr friend URI operator/(URI const& base, std::string_view ref) noexcept
712 {
713 return base / URI(ref);
714 }
715
721 [[nodiscard]] constexpr static std::string decode(std::string_view rhs)
722 {
723 auto r = std::string{rhs};
724
725 for (auto i = r.find('%'); i != std::string::npos; i = r.find('%', i)) {
726 // This may throw a parse_error, if not hexadecimal
727 auto c = from_string<uint8_t>(r.substr(i + 1, 2), 16);
728
729 // Replace the % encoded character.
730 r.replace(i, 3, 1, char_cast<char>(c));
731
732 // Skip over encoded-character.
733 ++i;
734 }
735
736 return r;
737 }
738
745 [[nodiscard]] constexpr static std::string decode(const_iterator first, const_iterator last)
746 {
747 return decode(std::string_view{first, last});
748 }
749
757 template<char... Extras, typename It, typename ItEnd>
758 [[nodiscard]] constexpr static std::string encode(It first, ItEnd last) noexcept
759 {
760 auto r = std::string{};
761 if constexpr (requires { std::distance(first, last); }) {
762 r.reserve(std::distance(first, last));
763 }
764
765 for (auto it = first; it != last; ++it) {
766 hilet c = *it;
767 // clang-format off
768 if (((
769 (c >= 'a' and c <= 'z') or
770 (c >= 'A' and c <= 'Z') or
771 (c >= '0' and c <= '9') or
772 c == '-' or c == '.' or c == '_' or c == '~'
773 ) or ... or (c == Extras))) {
774 r += c;
775
776 } else {
777 r += '%';
778 auto uc = char_cast<uint8_t>(c);
779 if (auto nibble = narrow_cast<char>(uc >> 4); nibble <= 9) {
780 r += '0' + nibble;
781 } else {
782 r += 'A' + nibble - 10;
783 }
784 if (auto nibble = narrow_cast<char>(uc & 0xf); nibble <= 9) {
785 r += '0' + nibble;
786 } else {
787 r += 'A' + nibble - 10;
788 }
789 }
790 // clang-format on
791 }
792
793 return r;
794 }
795
802 template<char... Extras, typename Range>
803 [[nodiscard]] constexpr static std::string encode(Range&& range) noexcept
804 {
805 return encode<Extras...>(std::ranges::begin(range), std::ranges::end(range));
806 }
807
808private:
809 std::optional<std::string> _scheme;
810 std::optional<authority_type> _authority;
811 path_type _path;
812 std::optional<std::string> _query;
813 std::optional<std::string> _fragment;
814
815 [[nodiscard]] constexpr friend size_t to_string_size(URI const& rhs) noexcept
816 {
817 auto size = 0_uz;
818 if (rhs._scheme) {
819 size += rhs._scheme->size() + 1;
820 }
821 if (rhs._authority) {
822 size += to_string_size(*rhs._authority) + 2;
823 }
824 size += to_string_size(rhs._path);
825
826 if (rhs._query) {
827 size += rhs._query->size() + 1;
828 }
829 if (rhs._fragment) {
830 size += rhs._fragment->size() + 1;
831 }
832
833 return size;
834 }
835
836 [[nodiscard]] constexpr static bool is_scheme_start(char c) noexcept
837 {
838 return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z');
839 }
840
841 [[nodiscard]] constexpr static bool is_scheme(char c) noexcept
842 {
843 return is_scheme_start(c) or (c >= '0' and c <= '9') or c == '+' or c == '-' or c == '.';
844 }
845
846 [[nodiscard]] constexpr static void validate_scheme(std::string_view str)
847 {
848 if (str.empty()) {
849 throw uri_error("The scheme-component is not allowed to be empty (it is allowed to not exist).");
850 }
851 if (not is_scheme_start(str.front())) {
852 throw uri_error("The scheme-component does not start with [a-zA-Z].");
853 }
854 for (auto c : str) {
855 if (not is_scheme(c)) {
856 throw uri_error("The scheme-component contains a character outside [a-zA-Z0-9.+-].");
857 }
858 }
859 }
860
861 [[nodiscard]] constexpr static void validate_path(path_type const& path, bool has_authority)
862 {
863 if (has_authority) {
864 if (not(path.empty() or path.absolute())) {
865 throw uri_error("A path-component in a URI with an authority-component must be empty or absolute.");
866 }
867 } else if (path.double_absolute()) {
868 throw uri_error("A path-component in a URI without an authority-component may not start with a double slash '//'.");
869 }
870 }
871
878 [[nodiscard]] constexpr const_iterator parse_scheme(const_iterator first, const_iterator last)
879 {
880 for (auto it = first; it != last; ++it) {
881 if (hilet c = *it; c == ':') {
882 set_scheme(std::string{first, it});
883 return it + 1; // Skip over ':'.
884
885 } else if (c == '/' or c == '?' or c == '#') {
886 // Invalid character, this is not a scheme.
887 return first;
888 }
889 }
890
891 // Reached at end of URI, this is not a scheme.
892 return first;
893 }
894
895 [[nodiscard]] constexpr const_iterator parse_authority(const_iterator first, const_iterator last)
896 {
897 for (auto it = first; it != last; it++) {
898 if (hilet c = *it; c == '/' or c == '?' or c == '#') {
899 set_authority(authority_type{std::string_view{first, it}});
900 return it;
901 }
902 }
903
904 set_authority(authority_type{std::string_view{first, last}});
905 return last;
906 }
907
908 [[nodiscard]] constexpr const_iterator parse_path(const_iterator first, const_iterator last)
909 {
910 for (auto it = first; it != last; it++) {
911 if (hilet c = *it; c == '?' or c == '#') {
912 set_path(path_type{std::string_view{first, it}});
913 return it;
914 }
915 }
916
917 set_path(path_type{std::string_view{first, last}});
918 return last;
919 }
920
921 [[nodiscard]] constexpr const_iterator parse_query(const_iterator first, const_iterator last)
922 {
923 for (auto it = first; it != last; it++) {
924 if (hilet c = *it; c == '#') {
925 set_query(URI::decode(first, it));
926 return it;
927 }
928 }
929
930 set_query(URI::decode(first, last));
931 return last;
932 }
933
934 [[nodiscard]] constexpr const_iterator parse_fragment(const_iterator first, const_iterator last)
935 {
936 set_fragment(URI::decode(first, last));
937 return last;
938 }
939
940 constexpr void parse(std::string_view str)
941 {
942 auto first = str.cbegin();
943 auto last = str.cend();
944 auto it = parse_scheme(first, last);
945
946 if (std::distance(it, last) >= 2 and it[0] == '/' and it[1] == '/') {
947 it += 2;
948 it = parse_authority(it, last);
949 }
950
951 it = parse_path(it, last);
952
953 if (it != last and *it == '?') {
954 it = parse_query(++it, last);
955 }
956
957 if (it != last and *it == '#') {
958 it = parse_fragment(++it, last);
959 }
960 }
961
962 friend struct std::hash<URI>;
963};
964
965#undef HI_PCHAR
966#undef HI_SUB_DELIM
967
968}} // namespace hi::v1
969
970template<>
971struct std::hash<hi::URI> {
972 [[nodiscard]] size_t operator()(hi::URI const& rhs) const noexcept
973 {
974 return std::hash<std::string>{}(to_string(rhs));
975 }
976};
977
978template<typename CharT>
979struct std::formatter<hi::URI, CharT> : std::formatter<std::string, CharT> {
980 auto format(hi::URI const& t, auto& fc) const
981 {
982 return std::formatter<std::string, CharT>::format(to_string(t), fc);
983 }
984};
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
A Uniform Resource Identifier.
Definition URI.hpp:39
static constexpr std::string decode(std::string_view rhs)
URI percent-encoding decode function.
Definition URI.hpp:721
constexpr URI(const char *str)
Construct a URI from a string.
Definition URI.hpp:513
static constexpr std::string decode(const_iterator first, const_iterator last)
URI percent-encoding decode function.
Definition URI.hpp:745
constexpr std::optional< std::string > const & query() const noexcept
Get the query-component of the URI.
Definition URI.hpp:595
constexpr std::optional< std::string > const & fragment() const noexcept
Get the fragment-component of the URI.
Definition URI.hpp:610
static constexpr std::string encode(Range &&range) noexcept
URI encode a component.
Definition URI.hpp:803
static constexpr std::string encode(It first, ItEnd last) noexcept
URI encode a component.
Definition URI.hpp:758
constexpr std::optional< authority_type > const & authority() const noexcept
Get the authority-component of the URI.
Definition URI.hpp:552
constexpr URI(std::string const &str)
Construct a URI from a string.
Definition URI.hpp:505
constexpr URI & remove_filename() noexcept
Remove the filename part of the path.
Definition URI.hpp:585
constexpr std::optional< std::string > const & scheme() const noexcept
Get the scheme-component of the URI.
Definition URI.hpp:529
constexpr URI & set_scheme(std::optional< std::string > const &rhs)
Get the scheme-component of the URI.
Definition URI.hpp:537
Definition URI.hpp:44
A path type.
Definition URI.hpp:270
constexpr path_type & remove_filename() noexcept
Remove the filename part of the path.
Definition URI.hpp:330
constexpr friend std::string to_string(path_type const &rhs, bool has_scheme=false) noexcept
Convert the URI path component to a string.
Definition URI.hpp:457
constexpr friend path_type remove_dot_segments(path_type path) noexcept
Definition URI.hpp:393
Definition exception_intf.hpp:208
std::string back(std::string ... args)
T cbegin(T... args)
std::string clear(std::string ... args)
T distance(T... args)
T emplace_back(T... args)
T empty(T... args)
T cend(T... args)
T erase(T... args)
std::string front(std::string ... args)
T merge(T... args)
T pop_back(T... args)
T ref(T... args)
T reserve(T... args)
std::string size(std::string ... args)
T to_string(T... args)