#pragma once #include #include #include #include #include #include #include namespace std { template std::strong_ordering operator<=>(T const & lhs, T const & rhs) { if (lhs < rhs) { return std::strong_ordering::less; } if (lhs > rhs) { return std::strong_ordering::greater; } return std::strong_ordering::equal; } } namespace jvalidate::detail { class Pointer { public: Pointer() = default; Pointer(std::vector> const & tokens) : tokens_(tokens) {} Pointer(std::string_view path) { for (size_t p = path.find('/'); p != std::string::npos; path.remove_prefix(p + 1), p = path.find('/')) { std::string token(path.substr(0, p)); if (token.find_first_not_of("0123456789") == std::string::npos) { tokens_.emplace_back(std::stoull(token)); } else { tokens_.emplace_back(token); } } } Pointer parent() const { return Pointer({tokens_.begin(), tokens_.end() - 1}); } Pointer & operator/=(Pointer const & relative) { tokens_.insert(tokens_.end(), relative.tokens_.begin(), relative.tokens_.end()); return *this; } Pointer operator/(Pointer const & relative) const { return Pointer(*this) /= relative; } Pointer & operator/=(std::string_view key) { tokens_.emplace_back(std::string(key)); return *this; } Pointer operator/(std::string_view key) const { return Pointer(*this) /= key; } Pointer & operator/=(size_t index) { tokens_.emplace_back(index); return *this; } Pointer operator/(size_t index) const { return Pointer(*this) /= index; } friend std::ostream & operator<<(std::ostream & os, Pointer const & self) { for (auto const & elem : self.tokens_) { std::visit([&os](auto const & v) { os << '/' << v; }, elem); } return os; } auto operator<=>(Pointer const &) const = default; private: std::vector> tokens_{}; }; }