Program Listing for File IRIView.cpp¶
↰ Return to documentation for file (src/rdf4cpp/IRIView.cpp)
#include "IRIView.hpp"
#include <uni_algo/all.h>
#include <rdf4cpp/util/CharMatcher.hpp>
namespace rdf4cpp {
IRIView::IRIView(std::string_view iri) noexcept : data(iri) {
}
std::string_view IRIView::apply(const IRIView::IRIPart &r) const noexcept {
return data.substr(r.start, r.len);
}
std::optional<std::string_view> IRIView::apply_opt(const IRIView::IRIPart &r) const noexcept {
if (r.defined)
return apply(r);
return std::nullopt;
}
IRIView::IRIPart IRIView::get_scheme_part() const noexcept {
auto c = data.find(':');
if (c == std::string_view::npos)
return {0, 0, false};
auto s = data.find('/');
if (c > s)
return {0, 0, false};
return {0, c, true};
}
std::optional<std::string_view> IRIView::scheme() const noexcept {
return apply_opt(get_scheme_part());
}
bool IRIView::is_relative() const noexcept {
return !get_scheme_part().defined;
}
IRIView::IRIPart IRIView::get_authority_part(const IRIPart &scheme) const noexcept {
auto d = data;
auto s = scheme.start + scheme.len;
if (s > 0) {
++s;
d = d.substr(s);
}
if (!d.starts_with("//"))
return {s, 0, false};
d = d.substr(2);
s += 2;
auto e = d.find_first_of("/#?");
if (e == std::string_view::npos)
e = d.length();
return {s, e, true};
}
std::optional<std::string_view> IRIView::authority() const noexcept {
return apply_opt(get_authority_part(get_scheme_part()));
}
IRIView::IRIPart IRIView::get_path_part(const IRIPart &auth) const noexcept {
auto b = auth.start + auth.len;
auto d = data.substr(b);
if (auth.len > 0 && !d.starts_with('/'))
return {b, 0, true};
auto e = d.find_first_of("#?");
if (e == std::string_view::npos)
e = d.length();
return {b, e, true};
}
std::string_view IRIView::path() const noexcept {
return apply(get_path_part(get_authority_part(get_scheme_part())));
}
IRIView::IRIPart IRIView::get_query_part(const IRIPart &path) const noexcept {
auto b = path.start + path.len;
auto d = data.substr(b);
if (!d.starts_with('?'))
return {b, 0, false};
d = d.substr(1);
++b;
auto e = d.find_first_of('#');
if (e == std::string_view::npos)
e = d.length();
return {b, e, true};
}
std::optional<std::string_view> IRIView::query() const noexcept {
return apply_opt(get_query_part(get_path_part(get_authority_part(get_scheme_part()))));
}
IRIView::IRIPart IRIView::get_fragment_part(const IRIPart &query) const noexcept {
auto b = query.start + query.len;
auto d = data.substr(b);
if (!d.starts_with('#'))
return {b, d.length(), false};
return {b + 1, d.length() - 1, true};
}
std::optional<std::string_view> IRIView::fragment() const noexcept {
return apply_opt(get_fragment_part(get_query_part(get_path_part(get_authority_part(get_scheme_part())))));
}
IRIView::AllParts IRIView::all_parts() const noexcept {
auto s = get_scheme_part();
auto a = get_authority_part(s);
auto p = get_path_part(a);
auto q = get_query_part(p);
auto f = get_fragment_part(q);
return {apply_opt(s), apply_opt(a), apply(p), apply_opt(q), apply_opt(f)};
}
std::string_view IRIView::to_absolute() const noexcept {
auto f = get_fragment_part(get_query_part(get_path_part(get_authority_part(get_scheme_part()))));
if (!f.defined)
return data;
return data.substr(0, f.start - 1);
}
IRIView::IRIPart IRIView::get_userinfo_part(const IRIView::IRIPart &auth) const noexcept {
if (!auth.defined)
return {0, 0, false};
auto d = apply(auth);
auto e = d.find('@');
if (e == std::string_view::npos)
return {auth.start, 0, false};
return {auth.start, e, true};
}
std::optional<std::string_view> IRIView::userinfo() const noexcept {
return apply_opt(get_userinfo_part(get_authority_part(get_scheme_part())));
}
IRIView::IRIPart IRIView::get_host_part(const IRIView::IRIPart &auth, const IRIView::IRIPart &uinfo) const noexcept {
if (!auth.defined)
return {0, 0, false};
auto d = apply(auth);
auto b = uinfo.start + uinfo.len;
if (uinfo.defined) {
d = d.substr(uinfo.len + 1);
++b;
}
auto e = d.find_last_of(':');
if (e == std::string_view::npos || d.find(']', e) != std::string_view::npos)
return {b, d.length(), true}; // :] or no : at all
return {b, e, true}; // ]: or :
}
std::optional<std::string_view> IRIView::host() const noexcept {
auto a = get_authority_part(get_scheme_part());
return apply_opt(get_host_part(a, get_userinfo_part(a)));
}
IRIView::IRIPart IRIView::get_port_part(const IRIView::IRIPart &auth, const IRIView::IRIPart &host) const noexcept {
if (!auth.defined)
return {0, 0, false};
auto d = apply(auth);
d = d.substr(host.start - auth.start + host.len);
auto b = host.start + host.len;
if (d.starts_with(':'))
return {b + 1, d.length() - 1, true};
return {b, 0, false};
}
std::optional<std::string_view> IRIView::port() const noexcept {
auto a = get_authority_part(get_scheme_part());
return apply_opt(get_port_part(a, get_host_part(a, get_userinfo_part(a))));
}
IRIView::AuthorityParts IRIView::all_authority_parts() const noexcept {
auto a = get_authority_part(get_scheme_part());
auto ui = get_userinfo_part(a);
auto ho = get_host_part(a, ui);
auto po = get_port_part(a, ho);
return {apply_opt(ui), apply_opt(ho), apply_opt(po)};
}
IRIFactoryError IRIView::quick_validate(bool allow_relative) const noexcept {
using namespace util::char_matcher_detail;
auto [scheme, auth, path, query, frag] = all_parts();
if (!scheme.has_value() && !allow_relative)
return IRIFactoryError::Relative;
static constexpr auto scheme_pattern = ascii_alphanum_matcher | ASCIIPatternMatcher{"+-."};
if (scheme.has_value() && !match<scheme_pattern, una::views::utf8>(*scheme))
return IRIFactoryError::InvalidScheme;
auto [userinfo, host, port] = all_authority_parts();
static constexpr auto userinfo_pattern = i_unreserved_matcher | sub_delims_matcher | ASCIIPatternMatcher{"%:"};
if (userinfo.has_value() && !match<userinfo_pattern, una::views::utf8>(*userinfo))
return IRIFactoryError::InvalidUserinfo;
static constexpr auto host_pattern = i_unreserved_matcher | sub_delims_matcher | ASCIIPatternMatcher{"%[]:"};
if (host.has_value() && !match<host_pattern, una::views::utf8>(*host))
return IRIFactoryError::InvalidHost;
static constexpr ASCIINumMatcher port_pattern{};
if (port.has_value() && !match<port_pattern, una::views::utf8>(*port))
return IRIFactoryError::InvalidPort;
static constexpr auto path_pattern = i_unreserved_matcher | sub_delims_matcher | ASCIIPatternMatcher{"%:@/"};
if (!match<path_pattern, una::views::utf8>(path))
return IRIFactoryError::InvalidPath;
static constexpr auto query_pattern = i_unreserved_matcher | sub_delims_matcher | IPrivateMatcher{} | ASCIIPatternMatcher{"%:@/?"};
if (query.has_value() && !match<query_pattern, una::views::utf8>(*query))
return IRIFactoryError::InvalidQuery;
static constexpr auto frag_pattern = i_unreserved_matcher | sub_delims_matcher | ASCIIPatternMatcher{"%:@/?"};
if (frag.has_value() && !match<frag_pattern, una::views::utf8>(*frag))
return IRIFactoryError::InvalidFragment;
return IRIFactoryError::Ok;
}
}