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/algorithm.hpp"
13#include "../macros.hpp"
14#include <string>
15#include <optional>
16#include <ranges>
17#include <vector>
18#include <format>
19#include <string_view>
20#include <string>
21#include <compare>
22#include <ostream>
23
24hi_export_module(hikogui.path.URI);
25
26hi_export namespace hi { inline namespace v1 {
27
28#define HI_SUB_DELIM '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '='
29#define HI_PCHAR HI_SUB_DELIM, ':', '@'
30
45class URI {
46private:
47 using const_iterator = std::string_view::const_iterator;
48
49public:
51 public:
52 constexpr authority_type() noexcept = default;
53 constexpr authority_type(authority_type const&) noexcept = default;
54 constexpr authority_type(authority_type&&) noexcept = default;
55 constexpr authority_type& operator=(authority_type const&) noexcept = default;
56 constexpr authority_type& operator=(authority_type&&) noexcept = default;
57
58 constexpr authority_type(std::string_view const& rhs) noexcept
59 {
60 parse(rhs);
61 }
62
63 // constexpr void normalize(std::optional<std::string> const& scheme) noexcept
64 //{
65 // hi_not_implemented();
66 // }
67
68 [[nodiscard]] constexpr std::optional<std::string> const& userinfo() const noexcept
69 {
70 return _userinfo;
71 }
72
73 constexpr authority_type& set_userinfo(std::optional<std::string> const& rhs) noexcept
74 {
75 _userinfo = rhs;
76 return *this;
77 }
78
79 [[nodiscard]] constexpr std::string const& host() const noexcept
80 {
81 return _host;
82 }
83
84 constexpr authority_type& set_host(std::string const& rhs)
85 {
86 validate_host(rhs);
87 _host = to_lower(rhs);
88 return *this;
89 }
90
91 [[nodiscard]] constexpr std::optional<std::string> const& port() const noexcept
92 {
93 return _port;
94 }
95
96 constexpr authority_type& set_port(std::optional<std::string> const& rhs)
97 {
98 if (rhs) {
99 validate_port(*rhs);
100 _port = *rhs;
101 } else {
102 _port = {};
103 }
104 return *this;
105 }
106
107 [[nodiscard]] constexpr friend bool operator==(authority_type const&, authority_type const&) noexcept = default;
108 [[nodiscard]] constexpr friend auto operator<=>(authority_type const&, authority_type const&) noexcept = default;
109
110 [[nodiscard]] constexpr friend size_t to_string_size(authority_type const& rhs) noexcept
111 {
112 auto size = 0_uz;
113 if (rhs._userinfo) {
114 size += rhs._userinfo->size() + 1;
115 }
116 size += rhs._host.size();
117 if (rhs._port) {
118 size += rhs._port->size() + 1;
119 }
120 return size;
121 }
122
123 [[nodiscard]] constexpr friend std::string to_string(authority_type const& rhs) noexcept
124 {
125 auto r = std::string{};
126
127 if (rhs._userinfo) {
128 r += URI::encode<HI_SUB_DELIM, ':'>(*rhs._userinfo);
129 r += '@';
130 }
131
132 if (rhs._host.empty() or rhs._host.front() != '[') {
133 r += URI::encode<HI_SUB_DELIM>(rhs._host);
134 } else {
135 r += URI::encode<HI_SUB_DELIM, '[', ']', ':'>(rhs._host);
136 }
137
138 if (rhs._port) {
139 r += ':';
140 r += *rhs._port;
141 }
142
143 return r;
144 }
145
146 private:
147 std::optional<std::string> _userinfo = {};
148 std::string _host = {};
149 std::optional<std::string> _port = {};
150
151 constexpr static void validate_host(std::string_view str)
152 {
153 if (str.starts_with('[') and not str.ends_with(']')) {
154 throw uri_error("The host-component starts with '[' has missing ']' at end");
155 } else if (str.ends_with(']') and str.starts_with('[')) {
156 throw uri_error("The host-component ends with ']' has missing '[' at start");
157 }
158 }
159
160 constexpr static void validate_port(std::string_view str)
161 {
162 for (auto c : str) {
163 if (not(c >= '0' and c <= '9')) {
164 throw uri_error("The port-component contains a non-digit.");
165 }
166 }
167 }
168
176 [[nodiscard]] constexpr const_iterator parse_userinfo(const_iterator first, const_iterator last) noexcept
177 {
178 for (auto it = first; it != last; ++it) {
179 if (auto const c = *it; c == '@') {
180 set_userinfo(URI::decode(first, it));
181 return it + 1; // Skip over '@'.
182 }
183 }
184
185 // Reached at end of URI, this is not a userinfo.
186 return first;
187 }
188
195 [[nodiscard]] constexpr const_iterator parse_host(const_iterator first, const_iterator last) noexcept
196 {
197 if (first == last) {
198 return first;
199 }
200
201 auto it = first;
202 if (*it == '[') {
203 while (it != last) {
204 if (*it == ']') {
205 set_host(URI::decode(first, it + 1));
206 return it + 1; // Skip over ']'.
207 }
208 }
209 // End of URI mean this is not a host, interpret as path instead.
210 return first;
211
212 } else {
213 for (; it != last; ++it) {
214 if (auto const c = *it; c == ':') {
215 // End of host.
216 set_host(URI::decode(first, it));
217 return it;
218 }
219 }
220
221 // End of URI means that the host is the last part of the URI
222 set_host(URI::decode(first, last));
223 return last;
224 }
225 }
226
227 [[nodiscard]] constexpr const_iterator parse_port(const_iterator first, const_iterator last) noexcept
228 {
229 set_port(std::string{first, last});
230 return last;
231 }
232
233 constexpr void parse(std::string_view rhs) noexcept
234 {
235 auto first = rhs.cbegin();
236 auto last = rhs.cend();
237 auto it = parse_userinfo(first, last);
238 it = parse_host(it, last);
239
240 if (it != last and *it == ':') {
241 it = parse_port(++it, last);
242 }
243 }
244 };
245
276 class path_type : public std::vector<std::string> {
277 public:
278 constexpr path_type() noexcept = default;
279 constexpr path_type(path_type const&) noexcept = default;
280 constexpr path_type(path_type&&) noexcept = default;
281 constexpr path_type& operator=(path_type const&) noexcept = default;
282 constexpr path_type& operator=(path_type&&) noexcept = default;
283
284 [[nodiscard]] constexpr static std::vector<std::string> parse(std::string_view str)
285 {
286 auto r = make_vector<std::string>(std::views::transform(std::views::split(str, std::string_view{"/"}), [](auto&& x) {
287 return URI::decode(std::string_view{std::ranges::begin(x), std::ranges::end(x)});
288 }));
289
290 if (r.size() == 1 and r.front().empty()) {
291 // An empty string will evaluate to a single segment.
292 r.clear();
293 }
294 if (not r.empty() and (r.back() == "." or r.back() == ".." or r.back() == "**")) {
295 // ".", ".." and "**" are directories always terminate with a slash.
296 r.emplace_back();
297 }
298
299 return r;
300 }
301
302 constexpr path_type(std::string_view str) noexcept : std::vector<std::string>(parse(str))
303 {
304 hi_axiom(holds_invariant());
305 }
306
307 [[nodiscard]] constexpr bool absolute() const noexcept
308 {
309 return size() >= 2 and front().empty();
310 }
311
312 [[nodiscard]] constexpr bool double_absolute() const noexcept
313 {
314 return size() >= 3 and (*this)[0].empty() and (*this)[1].empty();
315 }
316
317 [[nodiscard]] constexpr bool is_root() const noexcept
318 {
319 return size() == 2 and (*this)[0].empty() and (*this)[1].empty();
320 }
321
322 [[nodiscard]] constexpr std::optional<std::string> filename() const noexcept
323 {
324 if (empty() or back().empty()) {
325 return {};
326 } else {
327 return back();
328 }
329 }
330
336 constexpr path_type& remove_filename() noexcept
337 {
338 switch (size()) {
339 case 0: // Don't remove a filename from an empty path.
340 break;
341 case 1: // relative filename, make the path empty.
342 clear();
343 break;
344 default: // relative or absolute directory with optional filename. Just empty the last path segment.
345 back().clear();
346 }
347 hi_axiom(holds_invariant());
348 return *this;
349 }
350
351 [[nodiscard]] constexpr friend path_type merge(path_type base, path_type const& ref, bool base_has_authority) noexcept
352 {
353 if (base_has_authority and base.empty()) {
354 // A URL with an authority and empty path is implicitly the root path.
355 base.emplace_back();
356 base.emplace_back();
357 }
358
359 if (not base.empty()) {
360 // Remove the (possibly empty) filename from the base.
361 base.pop_back();
362 }
363 base.insert(base.cend(), ref.cbegin(), ref.cend());
364
365 if (base.size() == 1 and base.front().empty()) {
366 // Empty ref-path added to root base-path, fix by appending an empty filename.
367 base.emplace_back();
368 }
369
370 hi_axiom(base.holds_invariant());
371 return base;
372 }
373
399 [[nodiscard]] constexpr friend path_type remove_dot_segments(path_type path) noexcept
400 {
401 for (auto it = path.cbegin(); it != path.cend();) {
402 if (*it == ".") {
403 // Remove any "." from the path.
404 it = path.erase(it);
405
406 } else if (*it == "..") {
407 if (it == path.cbegin()) {
408 // Remove the ".." at the start of a relative path.
409 it = path.erase(it);
410
411 } else if (it - 1 == path.cbegin() and (it - 1)->empty()) {
412 // Remove just the ".." at the start of an absolute path.
413 it = path.erase(it);
414
415 } else {
416 // Remove ".." and the segment in front of it.
417 it = path.erase(it - 1, it + 1);
418 }
419 } else {
420 // Ignore other segments.
421 ++it;
422 }
423 }
424
425 if (path.size() == 1 and path.front().empty()) {
426 // After removing the ".." at the start of the path we are left with an empty segment.
427 path.clear();
428 }
429
430 hi_axiom(path.holds_invariant());
431 return path;
432 }
433
434 [[nodiscard]] constexpr bool holds_invariant() const noexcept
435 {
436 if (empty()) {
437 return true;
438 }
439
440 if (back() == "." or back() == ".." or back() == "**") {
441 // ".", ".." and "**" are always directories and may not be the last segment.
442 return false;
443 }
444 return true;
445 }
446
447 [[nodiscard]] constexpr friend size_t to_string_size(path_type const& rhs) noexcept
448 {
449 size_t r = 0_uz;
450 for (auto const& segment : rhs) {
451 r += segment.size();
452 }
453 r += rhs.size() + 1;
454 return r;
455 }
456
463 [[nodiscard]] constexpr friend std::string to_string(path_type const& rhs, bool has_scheme = false) noexcept
464 {
465 auto r = std::string{};
466 r.reserve(to_string_size(rhs));
467
468 auto segment_is_empty = false;
469 for (auto it = rhs.cbegin(); it != rhs.cend(); ++it) {
470 segment_is_empty = it->empty();
471
472 if (it == rhs.cbegin() and not has_scheme) {
473 r += URI::encode<HI_SUB_DELIM, '@'>(*it);
474 } else {
475 r += URI::encode<HI_PCHAR>(*it);
476 }
477 r += '/';
478 }
479
480 if (not r.empty() and not segment_is_empty) {
481 // The last path-component was a filename, remove the trailing slash '/'.
482 r.pop_back();
483 }
484 return r;
485 }
486 };
487
488 constexpr URI() noexcept = default;
489 constexpr URI(URI const&) noexcept = default;
490 constexpr URI(URI&&) noexcept = default;
491 constexpr URI& operator=(URI const&) noexcept = default;
492 constexpr URI& operator=(URI&&) noexcept = default;
493
500 constexpr explicit URI(std::string_view str)
501 {
502 parse(str);
503 }
504
511 constexpr explicit URI(std::string const& str) : URI(std::string_view{str}) {}
512
519 constexpr explicit URI(const char *str) : URI(std::string_view{str}) {}
520
521 [[nodiscard]] constexpr bool empty() const noexcept
522 {
523 return not _scheme and not _authority and _path.empty() and not _query and not _fragment;
524 }
525
526 constexpr operator bool() const noexcept
527 {
528 return not empty();
529 }
530
535 [[nodiscard]] constexpr std::optional<std::string> const& scheme() const noexcept
536 {
537 return _scheme;
538 }
539
543 constexpr URI& set_scheme(std::optional<std::string> const& rhs)
544 {
545 if (rhs) {
546 validate_scheme(*rhs);
547 _scheme = *rhs;
548 } else {
549 _scheme = {};
550 }
551 return *this;
552 }
553
558 [[nodiscard]] constexpr std::optional<authority_type> const& authority() const noexcept
559 {
560 return _authority;
561 }
562
563 constexpr URI& set_authority(std::optional<authority_type> const& rhs) noexcept
564 {
565 _authority = rhs;
566 return *this;
567 }
568
569 [[nodiscard]] constexpr path_type const& path() const noexcept
570 {
571 return _path;
572 }
573
574 constexpr URI& set_path(path_type const& rhs)
575 {
576 validate_path(rhs, to_bool(_authority));
577 _path = rhs;
578 return *this;
579 }
580
581 [[nodiscard]] constexpr std::optional<std::string> filename() const noexcept
582 {
583 return _path.filename();
584 }
585
591 constexpr URI& remove_filename() noexcept
592 {
593 _path.remove_filename();
594 return *this;
595 }
596
601 [[nodiscard]] constexpr std::optional<std::string> const& query() const noexcept
602 {
603 return _query;
604 }
605
606 constexpr URI& set_query(std::optional<std::string> const& rhs) noexcept
607 {
608 _query = rhs;
609 return *this;
610 }
611
616 [[nodiscard]] constexpr std::optional<std::string> const& fragment() const noexcept
617 {
618 return _fragment;
619 }
620
621 constexpr URI& set_fragment(std::optional<std::string> const& rhs) noexcept
622 {
623 _fragment = rhs;
624 return *this;
625 }
626
627 [[nodiscard]] constexpr friend std::string to_string(URI const& rhs) noexcept
628 {
629 auto r = std::string{};
630 r.reserve(to_string_size(rhs));
631
632 if (rhs._scheme) {
633 r += *rhs._scheme;
634 r += ':';
635 }
636
637 if (rhs._authority) {
638 r += '/';
639 r += '/';
640 r += to_string(*rhs._authority);
641 }
642
643 r += to_string(rhs._path, to_bool(rhs._scheme));
644
645 if (rhs._query) {
646 r += '?';
647 r += URI::encode<HI_PCHAR, '/', '?'>(*rhs._query);
648 }
649
650 if (rhs._fragment) {
651 r += '#';
652 r += URI::encode<HI_PCHAR, '/', '?'>(*rhs._fragment);
653 }
654
655 return r;
656 }
657
658 friend std::ostream& operator<<(std::ostream& lhs, URI const& rhs) noexcept
659 {
660 return lhs << to_string(rhs);
661 }
662
663 [[nodiscard]] constexpr friend bool operator==(URI const& lhs, URI const& rhs) noexcept = default;
664 [[nodiscard]] constexpr friend auto operator<=>(URI const& lhs, URI const& rhs) noexcept = default;
665
666 [[nodiscard]] constexpr friend URI operator/(URI const& base, URI const& ref) noexcept
667 {
668 auto target = URI{};
669
670 if (ref._scheme) {
671 target._scheme = ref._scheme;
672 target._authority = ref._authority;
673 target._path = remove_dot_segments(ref._path);
674 target._query = ref._query;
675 } else {
676 if (ref._authority) {
677 target._authority = ref._authority;
678 target._path = remove_dot_segments(ref._path);
679 target._query = ref._query;
680
681 } else {
682 if (ref._path.empty()) {
683 target._path = base._path;
684 if (ref._query) {
685 target._query = ref._query;
686 } else {
687 target._query = base._query;
688 }
689 } else {
690 if (ref._path.absolute()) {
691 target._path = remove_dot_segments(ref._path);
692 } else {
693 target._path = remove_dot_segments(merge(base._path, ref._path, to_bool(base._authority)));
694 }
695 target._query = ref._query;
696 }
697 target._authority = base._authority;
698 }
699 target._scheme = base._scheme;
700 }
701
702 target._fragment = ref._fragment;
703
704 return target;
705 }
706
707 [[nodiscard]] constexpr friend bool operator==(URI const& lhs, std::string_view rhs) noexcept
708 {
709 return lhs == URI(rhs);
710 }
711
712 [[nodiscard]] constexpr friend auto operator<=>(URI const& lhs, std::string_view rhs) noexcept
713 {
714 return lhs == URI(rhs);
715 }
716
717 [[nodiscard]] constexpr friend URI operator/(URI const& base, std::string_view ref) noexcept
718 {
719 return base / URI(ref);
720 }
721
727 [[nodiscard]] constexpr static std::string decode(std::string_view rhs)
728 {
729 auto r = std::string{rhs};
730
731 for (auto i = r.find('%'); i != std::string::npos; i = r.find('%', i)) {
732 // This may throw a parse_error, if not hexadecimal
733 auto c = from_string<uint8_t>(r.substr(i + 1, 2), 16);
734
735 // Replace the % encoded character.
736 r.replace(i, 3, 1, char_cast<char>(c));
737
738 // Skip over encoded-character.
739 ++i;
740 }
741
742 return r;
743 }
744
751 [[nodiscard]] constexpr static std::string decode(const_iterator first, const_iterator last)
752 {
753 return decode(std::string_view{first, last});
754 }
755
763 template<char... Extras, typename It, typename ItEnd>
764 [[nodiscard]] constexpr static std::string encode(It first, ItEnd last) noexcept
765 {
766 auto r = std::string{};
767 if constexpr (requires { std::distance(first, last); }) {
768 r.reserve(std::distance(first, last));
769 }
770
771 for (auto it = first; it != last; ++it) {
772 auto const c = *it;
773 // clang-format off
774 if (((
775 (c >= 'a' and c <= 'z') or
776 (c >= 'A' and c <= 'Z') or
777 (c >= '0' and c <= '9') or
778 c == '-' or c == '.' or c == '_' or c == '~'
779 ) or ... or (c == Extras))) {
780 r += c;
781
782 } else {
783 r += '%';
784 auto uc = char_cast<uint8_t>(c);
785 if (auto nibble = narrow_cast<char>(uc >> 4); nibble <= 9) {
786 r += '0' + nibble;
787 } else {
788 r += 'A' + nibble - 10;
789 }
790 if (auto nibble = narrow_cast<char>(uc & 0xf); nibble <= 9) {
791 r += '0' + nibble;
792 } else {
793 r += 'A' + nibble - 10;
794 }
795 }
796 // clang-format on
797 }
798
799 return r;
800 }
801
808 template<char... Extras, typename Range>
809 [[nodiscard]] constexpr static std::string encode(Range&& range) noexcept
810 {
811 return encode<Extras...>(std::ranges::begin(range), std::ranges::end(range));
812 }
813
814private:
815 std::optional<std::string> _scheme;
816 std::optional<authority_type> _authority;
817 path_type _path;
818 std::optional<std::string> _query;
819 std::optional<std::string> _fragment;
820
821 [[nodiscard]] constexpr friend size_t to_string_size(URI const& rhs) noexcept
822 {
823 auto size = 0_uz;
824 if (rhs._scheme) {
825 size += rhs._scheme->size() + 1;
826 }
827 if (rhs._authority) {
828 size += to_string_size(*rhs._authority) + 2;
829 }
830 size += to_string_size(rhs._path);
831
832 if (rhs._query) {
833 size += rhs._query->size() + 1;
834 }
835 if (rhs._fragment) {
836 size += rhs._fragment->size() + 1;
837 }
838
839 return size;
840 }
841
842 [[nodiscard]] constexpr static bool is_scheme_start(char c) noexcept
843 {
844 return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z');
845 }
846
847 [[nodiscard]] constexpr static bool is_scheme(char c) noexcept
848 {
849 return is_scheme_start(c) or (c >= '0' and c <= '9') or c == '+' or c == '-' or c == '.';
850 }
851
852 constexpr static void validate_scheme(std::string_view str)
853 {
854 if (str.empty()) {
855 throw uri_error("The scheme-component is not allowed to be empty (it is allowed to not exist).");
856 }
857 if (not is_scheme_start(str.front())) {
858 throw uri_error("The scheme-component does not start with [a-zA-Z].");
859 }
860 for (auto c : str) {
861 if (not is_scheme(c)) {
862 throw uri_error("The scheme-component contains a character outside [a-zA-Z0-9.+-].");
863 }
864 }
865 }
866
867 constexpr static void validate_path(path_type const& path, bool has_authority)
868 {
869 if (has_authority) {
870 if (not(path.empty() or path.absolute())) {
871 throw uri_error("A path-component in a URI with an authority-component must be empty or absolute.");
872 }
873 } else if (path.double_absolute()) {
874 throw uri_error("A path-component in a URI without an authority-component may not start with a double slash '//'.");
875 }
876 }
877
884 [[nodiscard]] constexpr const_iterator parse_scheme(const_iterator first, const_iterator last)
885 {
886 for (auto it = first; it != last; ++it) {
887 if (auto const c = *it; c == ':') {
888 set_scheme(std::string{first, it});
889 return it + 1; // Skip over ':'.
890
891 } else if (c == '/' or c == '?' or c == '#') {
892 // Invalid character, this is not a scheme.
893 return first;
894 }
895 }
896
897 // Reached at end of URI, this is not a scheme.
898 return first;
899 }
900
901 [[nodiscard]] constexpr const_iterator parse_authority(const_iterator first, const_iterator last)
902 {
903 for (auto it = first; it != last; it++) {
904 if (auto const c = *it; c == '/' or c == '?' or c == '#') {
905 set_authority(authority_type{std::string_view{first, it}});
906 return it;
907 }
908 }
909
910 set_authority(authority_type{std::string_view{first, last}});
911 return last;
912 }
913
914 [[nodiscard]] constexpr const_iterator parse_path(const_iterator first, const_iterator last)
915 {
916 for (auto it = first; it != last; it++) {
917 if (auto const c = *it; c == '?' or c == '#') {
918 set_path(path_type{std::string_view{first, it}});
919 return it;
920 }
921 }
922
923 set_path(path_type{std::string_view{first, last}});
924 return last;
925 }
926
927 [[nodiscard]] constexpr const_iterator parse_query(const_iterator first, const_iterator last)
928 {
929 for (auto it = first; it != last; it++) {
930 if (auto const c = *it; c == '#') {
931 set_query(URI::decode(first, it));
932 return it;
933 }
934 }
935
936 set_query(URI::decode(first, last));
937 return last;
938 }
939
940 [[nodiscard]] constexpr const_iterator parse_fragment(const_iterator first, const_iterator last)
941 {
942 set_fragment(URI::decode(first, last));
943 return last;
944 }
945
946 constexpr void parse(std::string_view str)
947 {
948 auto first = str.cbegin();
949 auto last = str.cend();
950 auto it = parse_scheme(first, last);
951
952 if (std::distance(it, last) >= 2 and it[0] == '/' and it[1] == '/') {
953 it += 2;
954 it = parse_authority(it, last);
955 }
956
957 it = parse_path(it, last);
958
959 if (it != last and *it == '?') {
960 it = parse_query(++it, last);
961 }
962
963 if (it != last and *it == '#') {
964 it = parse_fragment(++it, last);
965 }
966 }
967
968 friend struct std::hash<URI>;
969};
970
971#undef HI_PCHAR
972#undef HI_SUB_DELIM
973
974}} // namespace hi::v1
975
976template<>
977struct std::hash<hi::URI> {
978 [[nodiscard]] size_t operator()(hi::URI const& rhs) const noexcept
979 {
980 return std::hash<std::string>{}(to_string(rhs));
981 }
982};
983
984// XXX #617 MSVC bug does not handle partial specialization in modules.
985hi_export template<>
986struct std::formatter<hi::URI, char> : std::formatter<std::string, char> {
987 auto format(hi::URI const& t, auto& fc) const
988 {
989 return std::formatter<std::string, char>::format(to_string(t), fc);
990 }
991};
STL namespace.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
A Uniform Resource Identifier.
Definition URI.hpp:45
static constexpr std::string decode(std::string_view rhs)
URI percent-encoding decode function.
Definition URI.hpp:727
constexpr URI(const char *str)
Construct a URI from a string.
Definition URI.hpp:519
static constexpr std::string decode(const_iterator first, const_iterator last)
URI percent-encoding decode function.
Definition URI.hpp:751
constexpr std::optional< std::string > const & query() const noexcept
Get the query-component of the URI.
Definition URI.hpp:601
constexpr std::optional< std::string > const & fragment() const noexcept
Get the fragment-component of the URI.
Definition URI.hpp:616
static constexpr std::string encode(Range &&range) noexcept
URI encode a component.
Definition URI.hpp:809
static constexpr std::string encode(It first, ItEnd last) noexcept
URI encode a component.
Definition URI.hpp:764
constexpr std::optional< authority_type > const & authority() const noexcept
Get the authority-component of the URI.
Definition URI.hpp:558
constexpr URI(std::string const &str)
Construct a URI from a string.
Definition URI.hpp:511
constexpr URI & remove_filename() noexcept
Remove the filename part of the path.
Definition URI.hpp:591
constexpr std::optional< std::string > const & scheme() const noexcept
Get the scheme-component of the URI.
Definition URI.hpp:535
constexpr URI & set_scheme(std::optional< std::string > const &rhs)
Get the scheme-component of the URI.
Definition URI.hpp:543
Definition URI.hpp:50
A path type.
Definition URI.hpp:276
constexpr path_type & remove_filename() noexcept
Remove the filename part of the path.
Definition URI.hpp:336
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:463
constexpr friend path_type remove_dot_segments(path_type path) noexcept
Definition URI.hpp:399
Definition exception_intf.hpp:209
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)