#pragma once #include #include #include #include #include #include #include namespace jvalidate::detail { class Reference; class RootReference { private: friend class Reference; URI uri_; Anchor anchor_; public: RootReference() = default; explicit RootReference(URI const & uri, Anchor const & anchor = {}) : uri_(uri), anchor_(anchor) {} explicit RootReference(std::string_view ref) : RootReference(ref, discard_out) {} bool is_relative() const { return uri_.is_relative(); } URI const & uri() const { return uri_; } Anchor const & anchor() const { return anchor_; } friend std::ostream & operator<<(std::ostream & os, RootReference const & self) { return os << self.uri_ << '#' << self.anchor_; } auto operator<=>(RootReference const &) const = default; private: RootReference(std::string_view ref, out end) { end = std::string::npos; size_t end_of_uri = ref.find('#'); uri_ = URI(ref.substr(0, end_of_uri)); if (end_of_uri == std::string::npos) { return; } ref.remove_prefix(end_of_uri + 1); size_t const pointer_start = ref.find('/'); anchor_ = Anchor(ref.substr(0, pointer_start)); EXPECT_M(end || pointer_start == std::string::npos, "JSON-Pointer is illegal in this context"); if (pointer_start != std::string::npos) { end = pointer_start + end_of_uri + 1; } } }; class Reference { private: RootReference root_; Pointer pointer_; public: Reference() = default; explicit Reference(URI const & uri, Pointer const & pointer = {}) : root_(uri), pointer_(pointer) {} explicit Reference(URI const & uri, Anchor const & anchor, Pointer const & pointer = {}) : root_(uri, anchor), pointer_(pointer) {} explicit Reference(RootReference const & root, Pointer const & pointer = {}) : root_(root), pointer_(pointer) {} explicit Reference(std::string_view ref) { size_t pointer_start = 0; root_ = RootReference(ref, pointer_start); if (pointer_start != std::string::npos) { pointer_ = ref.substr(pointer_start); } } URI const & uri() const { return root_.uri(); } Anchor const & anchor() const { return root_.anchor(); } Pointer const & pointer() const { return pointer_; } RootReference const & root() const { return root_; } Reference parent() const { return Reference(root_, pointer_.parent()); } /** * @brief Delegate function for {@see Pointer::operator/=}, but returning * this Reference. */ Reference & operator/=(auto const & in) { return (pointer_ /= in, *this); } /** * @brief Delegate function for {@see Pointer::operator/}, but returning * a Reference. */ Reference operator/(auto const & in) const { return Reference(*this) /= in; } friend std::ostream & operator<<(std::ostream & os, Reference const & self) { return os << self.root_ << self.pointer_; } auto operator<=>(Reference const &) const = default; }; }