#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()); } Reference & operator/=(Pointer const & relative) { pointer_ /= relative; return *this; } Reference operator/(Pointer const & relative) const { return Reference(*this) /= relative; } Reference & operator/=(std::string_view key) { pointer_ /= key; return *this; } Reference operator/(std::string_view key) const { return Reference(*this) /= key; } Reference & operator/=(size_t index) { pointer_ /= index; return *this; } Reference operator/(size_t index) const { return Reference(*this) /= index; } friend std::ostream & operator<<(std::ostream & os, Reference const & self) { return os << self.root_ << self.pointer_; } auto operator<=>(Reference const &) const = default; }; }