simple_adapter.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #pragma once
  2. #include <unordered_map>
  3. #include <vector>
  4. #include <jvalidate/adapter.h>
  5. #include <jvalidate/detail/array_iterator.h>
  6. #include <jvalidate/detail/expect.h>
  7. #include <jvalidate/detail/object_iterator.h>
  8. #include <jvalidate/forward.h>
  9. #include <jvalidate/status.h>
  10. namespace jvalidate::adapter::detail {
  11. template <typename JSON, typename Adapter = AdapterFor<JSON>> class SimpleObjectAdapter {
  12. public:
  13. using underlying_iterator_t = decltype(std::declval<JSON>().begin());
  14. using const_iterator = JsonObjectIterator<underlying_iterator_t, Adapter>;
  15. SimpleObjectAdapter(JSON * value) : value_(value) {}
  16. size_t size() const { return value_ ? value_->size() : 0; }
  17. const_iterator find(std::string const & key) const {
  18. return std::find_if(begin(), end(), [key](auto const & kv) { return kv.first == key; });
  19. }
  20. bool contains(std::string const & key) const { return find(key) != end(); }
  21. Adapter operator[](std::string const & key) const {
  22. auto it = find(key);
  23. return it != end() ? it->second : Adapter();
  24. }
  25. const_iterator begin() const {
  26. return value_ ? const_iterator(value_->begin()) : const_iterator();
  27. }
  28. const_iterator end() const { return value_ ? const_iterator(value_->end()) : const_iterator(); }
  29. std::map<std::string_view, Adapter> operator*() const {
  30. using C = std::map<std::string_view, Adapter>;
  31. return value_ ? C(begin(), end()) : C();
  32. }
  33. protected:
  34. JSON * value() const { return value_; }
  35. JSON const & const_value() const { return value_ ? *value_ : AdapterTraits<JSON>::const_empty(); }
  36. private:
  37. JSON * value_;
  38. };
  39. template <typename JSON, typename Adapter = AdapterFor<JSON>> class SimpleArrayAdapter {
  40. public:
  41. using underlying_iterator_t = decltype(std::declval<JSON>().begin());
  42. using const_iterator = JsonArrayIterator<underlying_iterator_t, Adapter>;
  43. SimpleArrayAdapter(JSON * value) : value_(value) {}
  44. size_t size() const { return value_ ? value_->size() : 0; }
  45. Adapter operator[](size_t index) const {
  46. if (index > size()) {
  47. return Adapter();
  48. }
  49. auto it = begin();
  50. std::advance(it, index);
  51. return *it;
  52. }
  53. const_iterator begin() const {
  54. return value_ ? const_iterator(value_->begin()) : const_iterator();
  55. }
  56. const_iterator end() const { return value_ ? const_iterator(value_->end()) : const_iterator(); }
  57. std::vector<Adapter> operator*() const {
  58. using C = std::vector<Adapter>;
  59. return value_ ? C(begin(), end()) : C();
  60. }
  61. protected:
  62. JSON * value() const { return value_; }
  63. JSON const & const_value() const { return value_ ? *value_ : AdapterTraits<JSON>::const_empty(); }
  64. private:
  65. JSON * value_;
  66. };
  67. template <typename JSON, typename CRTP = AdapterFor<JSON>> class SimpleAdapter : public Adapter {
  68. public:
  69. static constexpr bool is_mutable =
  70. not std::is_const_v<JSON> && MutableObject<decltype(std::declval<CRTP>().as_object())>;
  71. using value_type = std::remove_const_t<JSON>;
  72. public:
  73. SimpleAdapter(JSON * value = nullptr) : value_(value) {}
  74. SimpleAdapter(JSON & value) : value_(&value) {}
  75. size_t array_size() const final { return self().as_array().size(); }
  76. CRTP operator[](size_t index) const { return self().as_array()[index]; }
  77. detail::SimpleArrayAdapter<JSON> as_array() const { return value_; }
  78. Status apply_array(AdapterCallback const & cb) const final {
  79. Status result = Status::Noop;
  80. for (auto const & child : self().as_array()) {
  81. result = cb(child) & result;
  82. }
  83. return result;
  84. }
  85. size_t object_size() const final { return self().as_object().size(); }
  86. bool contains(std::string const & key) const { return self().as_object().contains(key); }
  87. CRTP operator[](std::string const & key) const { return self().as_object()[key]; }
  88. detail::SimpleObjectAdapter<JSON, CRTP> as_object() const { return value_; }
  89. Status apply_object(ObjectAdapterCallback const & cb) const final {
  90. Status result = Status::Noop;
  91. for (auto const & [key, child] : self().as_object()) {
  92. result = cb(key, child) & result;
  93. }
  94. return result;
  95. }
  96. std::unique_ptr<Const const> freeze() const final {
  97. return std::make_unique<GenericConst<value_type>>(const_value());
  98. }
  99. void assign(Const const & frozen) const requires(is_mutable) {
  100. EXPECT_M(value_ != nullptr, "Failed to create a new element in parent object");
  101. if (auto * this_frozen = dynamic_cast<GenericConst<value_type> const *>(&frozen)) {
  102. *value_ = this_frozen->value();
  103. return;
  104. }
  105. frozen.apply([this](Adapter const & adapter) {
  106. static_cast<CRTP const *>(this)->assign(adapter);
  107. return Status::Accept;
  108. });
  109. }
  110. auto operator<=>(SimpleAdapter const & rhs) const requires std::totally_ordered<JSON> {
  111. using ord = std::strong_ordering;
  112. if (value_ == rhs.value_) {
  113. return ord::equal;
  114. }
  115. if (value_ && rhs.value_) {
  116. if (*value_ < *rhs.value_) {
  117. return ord::less;
  118. }
  119. if (*rhs.value_ < *value_) {
  120. return ord::greater;
  121. }
  122. return ord::equal;
  123. }
  124. if (value_) {
  125. return type() == Type::Null ? ord::equivalent : ord::greater;
  126. }
  127. return rhs.type() == Type::Null ? ord::equivalent : ord::less;
  128. }
  129. bool equals(Adapter const & rhs, bool strict = false) const final {
  130. Type const rhs_type = rhs.type();
  131. if (strict && rhs_type != type()) {
  132. return false;
  133. }
  134. // TODO(samjaffe): Needs type coercion
  135. switch (rhs_type) {
  136. case Type::Null:
  137. return type() == Type::Null;
  138. case Type::Boolean:
  139. return rhs.as_boolean() == as_boolean();
  140. case Type::Integer:
  141. return rhs.as_integer() == as_integer();
  142. case Type::Number:
  143. return rhs.as_number() == as_number();
  144. case Type::String:
  145. return rhs.as_string() == as_string();
  146. case Type::Array: {
  147. auto array = this->as_array();
  148. if (rhs.array_size() != array.size()) {
  149. return false;
  150. }
  151. bool rval = true;
  152. rhs.apply_array([&, this, index = 0UL](adapter::Adapter const & elem) mutable {
  153. // Short-Circuit OK
  154. rval = rval && array[index].equals(elem, strict);
  155. ++index;
  156. return Status::Accept;
  157. });
  158. return rval;
  159. }
  160. case Type::Object: {
  161. auto object = this->as_object();
  162. if (rhs.object_size() != object.size()) {
  163. return false;
  164. }
  165. bool rval = true;
  166. rhs.apply_object([&, this](std::string const & key, adapter::Adapter const & elem) {
  167. // Short-Circuit OK
  168. rval = rval && object.contains(key) && object[key].equals(elem, strict);
  169. return Status::Accept;
  170. });
  171. return rval;
  172. }
  173. }
  174. }
  175. protected:
  176. JSON * value() const { return value_; }
  177. JSON const & const_value() const { return value_ ? *value_ : AdapterTraits<JSON>::const_empty(); }
  178. private:
  179. CRTP const & self() const { return static_cast<CRTP const &>(*this); }
  180. private:
  181. JSON * value_;
  182. };
  183. }