reference.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #pragma once
  2. #include <string>
  3. #include <string_view>
  4. #include <jvalidate/detail/anchor.h>
  5. #include <jvalidate/detail/expect.h>
  6. #include <jvalidate/detail/out.h>
  7. #include <jvalidate/detail/pointer.h>
  8. #include <jvalidate/uri.h>
  9. namespace jvalidate::detail {
  10. class Reference;
  11. class RootReference {
  12. private:
  13. friend class Reference;
  14. URI uri_;
  15. Anchor anchor_;
  16. public:
  17. RootReference() = default;
  18. explicit RootReference(URI const & uri, Anchor const & anchor = {})
  19. : uri_(uri), anchor_(anchor) {}
  20. explicit RootReference(std::string_view ref) : RootReference(ref, discard_out) {}
  21. bool is_relative() const { return uri_.is_relative(); }
  22. URI const & uri() const { return uri_; }
  23. Anchor const & anchor() const { return anchor_; }
  24. friend std::ostream & operator<<(std::ostream & os, RootReference const & self) {
  25. return os << self.uri_ << '#' << self.anchor_;
  26. }
  27. auto operator<=>(RootReference const &) const = default;
  28. private:
  29. RootReference(std::string_view ref, out<size_t> end) {
  30. end = std::string::npos;
  31. size_t end_of_uri = ref.find('#');
  32. uri_ = URI(ref.substr(0, end_of_uri));
  33. if (end_of_uri == std::string::npos) {
  34. return;
  35. }
  36. ref.remove_prefix(end_of_uri + 1);
  37. size_t const pointer_start = ref.find('/');
  38. anchor_ = Anchor(ref.substr(0, pointer_start));
  39. EXPECT_M(end || pointer_start == std::string::npos, "JSON-Pointer is illegal in this context");
  40. if (pointer_start != std::string::npos) {
  41. end = pointer_start + end_of_uri + 1;
  42. }
  43. }
  44. };
  45. class Reference {
  46. private:
  47. RootReference root_;
  48. Pointer pointer_;
  49. public:
  50. Reference() = default;
  51. explicit Reference(URI const & uri, Pointer const & pointer = {})
  52. : root_(uri), pointer_(pointer) {}
  53. explicit Reference(URI const & uri, Anchor const & anchor, Pointer const & pointer = {})
  54. : root_(uri, anchor), pointer_(pointer) {}
  55. explicit Reference(RootReference const & root, Pointer const & pointer = {})
  56. : root_(root), pointer_(pointer) {}
  57. explicit Reference(std::string_view ref) {
  58. size_t pointer_start = 0;
  59. root_ = RootReference(ref, pointer_start);
  60. if (pointer_start != std::string::npos) {
  61. pointer_ = ref.substr(pointer_start);
  62. }
  63. }
  64. URI const & uri() const { return root_.uri(); }
  65. Anchor const & anchor() const { return root_.anchor(); }
  66. Pointer const & pointer() const { return pointer_; }
  67. RootReference const & root() const { return root_; }
  68. Reference parent() const { return Reference(root_, pointer_.parent()); }
  69. /**
  70. * @brief Delegate function for {@see Pointer::operator/=}, but returning
  71. * this Reference.
  72. */
  73. Reference & operator/=(auto const & in) { return (pointer_ /= in, *this); }
  74. /**
  75. * @brief Delegate function for {@see Pointer::operator/}, but returning
  76. * a Reference.
  77. */
  78. Reference operator/(auto const & in) const { return Reference(*this) /= in; }
  79. friend std::ostream & operator<<(std::ostream & os, Reference const & self) {
  80. return os << self.root_ << self.pointer_;
  81. }
  82. auto operator<=>(Reference const &) const = default;
  83. };
  84. }