Wildmeshing Toolkit
merkle_tree_diff.cpp
Go to the documentation of this file.
1 #include "merkle_tree_diff.hpp"
4 #include "Hashable.hpp"
6 
7 namespace wmtk::utils {
8 namespace {
9 
10 template <typename T>
11 nlohmann::json attribute_detailed_data_diff(
14 {
15  nlohmann::json data;
16  if (a_a.dimension() != a_b.dimension()) {
17  data["dimension"] = {a_a.dimension(), a_b.dimension()};
18  return data;
19  }
20  const int64_t a_size = a_a.reserved_size();
21  const int64_t b_size = a_b.reserved_size();
22 
23  if (a_size != b_size) {
24  data["sizes"] = {a_size, b_size};
25  }
26 
27  const int64_t size = std::max(a_size, b_size);
28 
29  for (int64_t index = 0; index < size; ++index) {
30  auto write_value = [&](const auto& attr) -> std::vector<T> {
31  if (index >= attr.reserved_size()) {
32  return {};
33  }
34  std::vector<T> r(attr.dimension());
35  auto v = attr.const_vector_attribute(index);
36  std::copy(v.begin(), v.end(), r.begin());
37  return r;
38  };
39  if constexpr (std::is_same_v<T, wmtk::Rational>) {
40  // TODO:
41  } else {
42  nlohmann::json a_values = write_value(a_a);
43  nlohmann::json b_values = write_value(a_b);
44  if (a_values.size() == 0) {
45  a_values = {};
46  }
47  if (b_values.size() == 0) {
48  b_values = {};
49  }
50  if (a_values != b_values) {
51  nlohmann::json& mydat = data["values"].emplace_back();
52  mydat["index"] = index;
53  mydat["values"] = {a_values, b_values};
54  }
55  }
56  }
57 
58  return data;
59 }
61  const MerkleTreeInteriorNode& a,
62  const MerkleTreeInteriorNode& b,
63  bool detailed = false)
64 {
65  nlohmann::json diff;
66  auto a_child_hashables = a.child_hashables();
67  auto b_child_hashables = b.child_hashables();
68  for (const auto& [name, a_hashable_ptr] : a_child_hashables) {
69  if (auto it = b_child_hashables.find(name); it != b_child_hashables.end()) {
70  const auto& b_hashable_ptr = std::get<1>(*it);
71  auto cdiff_opt = merkle_tree_diff(*a_hashable_ptr, *b_hashable_ptr, detailed = true);
72  if (!cdiff_opt.has_value()) {
73  continue;
74  }
75  diff[name] = cdiff_opt.value();
76  }
77  }
78  return diff;
79 }
80 } // namespace
81 std::optional<nlohmann::json> merkle_tree_diff(const Hashable& a, const Hashable& b, bool detailed)
82 {
83  nlohmann::json diff;
84 
85  if (a.hash() == b.hash()) {
86  return {};
87  }
88  auto a_child_hashes = a.child_hashes();
89  auto b_child_hashes = b.child_hashes();
90 
91  // temporaries to store the left/right of something
92  nlohmann::json a_value;
93  nlohmann::json b_value;
94  for (const auto& [name, a_hash] : a_child_hashes) {
95  a_value = a_hash;
96  if (b_child_hashes.find(name) != b_child_hashes.end()) {
97  size_t b_hash = b_child_hashes[name];
98  if (a_hash == b_hash) {
99  continue;
100  }
101  b_value = b_hash;
102  } else {
103  b_value = nlohmann::json();
104  }
105  diff[name] = nlohmann::json::array({a_value, b_value});
106  }
107 
108  a_value = nlohmann::json();
109  for (const auto& [name, hash] : b_child_hashes) {
110  b_value = hash;
111  if (b_child_hashes.find(name) != b_child_hashes.end()) {
112  // covered in previous loop
113  continue;
114  }
115  diff[name] = nlohmann::json::array({a_value, b_value});
116  }
117 
118  // takes in some pointer of the type being cast to (just pass in nullptr
119  // this is just a hack to get around not having
120  // [&]<typename T>() {
121  // }
122  // try_cast<T>
123  // which is a cpp20 feature :(
124  auto try_cast = [&](auto&& type) {
125  using T = std::decay_t<decltype(*type)>;
126  std::optional<std::array<const T*, 2>> ret;
127  auto a_ptr = dynamic_cast<const T*>(&a), b_ptr = dynamic_cast<const T*>(&b);
128  if (a_ptr != nullptr && b_ptr != nullptr) {
129  ret = std::array<const T*, 2>{{a_ptr, b_ptr}};
130  }
131  return ret;
132  };
133 
134  // pass in a ptr to the desired type
135  if (auto merkle_pair_opt = try_cast((MerkleTreeInteriorNode*)(nullptr));
136  merkle_pair_opt.has_value()) {
137  const auto& m_pr = merkle_pair_opt.value();
138  const auto& m_a = *m_pr[0];
139  const auto& m_b = *m_pr[1];
140  auto cdiff = merkle_tree_diff(m_a, m_b, detailed);
141 
142  for (const auto& kv : cdiff.items()) {
143  diff[kv.key()] = kv.value();
144  }
145  }
146 
147  auto try_attr = [&](auto&& type) {
148  using T = std::decay_t<decltype(type)>;
149 
150  if (auto attr_pair_opt = try_cast((attribute::Attribute<T>*)(nullptr));
151  attr_pair_opt.has_value()) {
152  const auto& a_pr = attr_pair_opt.value();
153  const auto& a_a = *a_pr[0];
154  const auto& a_b = *a_pr[1];
155 
156  if (detailed) {
157  diff["details"] = attribute_detailed_data_diff(a_a, a_b);
158  }
159  // if (!cdiff.is_null()) {
160  // diff[name] = cdiff;
161  // }
162  }
163  };
164  try_attr(double());
165  try_attr(int64_t());
166  try_attr(char());
167  // try_attr(Rational());
168  return diff;
169 }
170 } // namespace wmtk::utils
This class stores data of type T in a vector.
Definition: Attribute.hpp:32
int64_t dimension() const
The number of values for each index.
Definition: Attribute.hpp:326
int64_t reserved_size() const
The total number of elements in a vector.
Definition: Attribute.cpp:73
virtual std::map< std::string, size_t > child_hashes() const
Definition: Hashable.cpp:32
virtual std::size_t hash() const
Definition: Hashable.cpp:15
std::optional< nlohmann::json > merkle_tree_diff(const Hashable &a, const Hashable &b, bool detailed)
nlohmann::json json
Definition: input.cpp:9