File indexing completed on 2026-05-27 07:24:14
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/definitions/indexing.hpp"
0013 #include "detray/definitions/math.hpp"
0014
0015
0016 #include <iterator>
0017 #include <sstream>
0018 #include <type_traits>
0019
0020 namespace detray {
0021
0022
0023 template <typename value_t>
0024 struct default_hash {
0025 using hash_type = std::size_t;
0026 using data_hasher = std::hash<value_t>;
0027 using node_hasher = std::hash<hash_type>;
0028
0029 auto operator()(const value_t &v) { return data_hasher{}(v); }
0030
0031 auto operator()(const hash_type &left, const hash_type &right) {
0032 return node_hasher{}(left) + node_hasher{}(right);
0033 }
0034 };
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 template <typename input_collection_t,
0046 typename data_t = typename input_collection_t::value_type,
0047 typename hash_function_t = default_hash<data_t>,
0048 typename hash_t =
0049 decltype(std::declval<hash_function_t>()(data_t{0})),
0050 template <typename> class vector_t = dvector>
0051 requires std::is_invocable_v<hash_function_t, data_t> &&
0052 std::is_invocable_v<hash_function_t, hash_t>
0053 class hash_tree {
0054 public:
0055 using hash_function = hash_function_t;
0056 using hash_type = hash_t;
0057
0058
0059 struct hashed_node {
0060 explicit hashed_node(hash_t hash) : _key(hash) {}
0061
0062 hash_t _key;
0063 dindex _parent{detail::invalid_value<dindex>()};
0064 dindex _left_child{detail::invalid_value<dindex>()};
0065 dindex _right_child{detail::invalid_value<dindex>()};
0066
0067 const hash_t &key() const { return _key; }
0068 hash_t &key() { return _key; }
0069
0070 void set_parent(dindex pi) { _parent = pi; }
0071
0072 void set_children(dindex lc, dindex rc) {
0073 _left_child = lc;
0074 _right_child = rc;
0075 }
0076 };
0077
0078
0079 hash_tree() = delete;
0080
0081
0082
0083
0084
0085 explicit hash_tree(const input_collection_t &data,
0086 const hash_function_t & = {}) {
0087 build(data);
0088 }
0089
0090
0091 ~hash_tree() = default;
0092
0093
0094
0095
0096 auto root() { return _tree.back().key(); }
0097
0098
0099 inline std::string to_string() const {
0100 std::stringstream ss;
0101 for (const auto &n : _tree) {
0102 ss << n.key() << std::endl;
0103 }
0104 return ss.str();
0105 };
0106
0107
0108 const vector_t<hashed_node> &tree() const { return _tree; }
0109
0110 private:
0111
0112 void build(const input_collection_t &input_data) noexcept(false) {
0113
0114 for (const auto &data : input_data) {
0115 _tree.emplace_back(_hash(data));
0116 }
0117
0118 if (input_data.size() % 2u != 0u) {
0119 _tree.emplace_back(_hash(0));
0120 }
0121
0122
0123
0124 auto n_levels = static_cast<dindex>(math::log(input_data.size()));
0125 _tree.reserve(2u * _tree.size() + n_levels);
0126
0127 build(_tree.begin(), static_cast<dindex>(_tree.size()));
0128 }
0129
0130
0131
0132
0133
0134 template <typename iterator_t>
0135 void build(iterator_t &&first_child, dindex n_prev_level) {
0136
0137 if (n_prev_level <= 1u) {
0138 return;
0139 }
0140
0141 auto last_child = first_child + static_cast<std::ptrdiff_t>(n_prev_level);
0142
0143
0144 for (auto current_child = first_child; current_child != last_child;
0145 current_child += 2u) {
0146 auto parent_digest =
0147 _hash(current_child->key(), (current_child + 1u)->key());
0148 hashed_node parent = _tree.emplace_back(parent_digest);
0149
0150
0151 current_child->set_parent(static_cast<dindex>(_tree.size()) - 1u);
0152 (current_child + 1)->set_parent(static_cast<dindex>(_tree.size()) - 1u);
0153
0154
0155 auto left_child_idx = std::distance(current_child, _tree.begin());
0156 parent.set_children(static_cast<dindex>(left_child_idx),
0157 static_cast<dindex>(left_child_idx) + 1u);
0158 }
0159 dindex n_level = n_prev_level / 2u;
0160
0161 if (n_level % 2u != 0u && n_level > 1u) {
0162 _tree.emplace_back(0);
0163 n_level++;
0164 }
0165
0166 build(last_child, n_level);
0167 }
0168
0169
0170 hash_function_t _hash{hash_function_t{}};
0171
0172
0173 vector_t<hashed_node> _tree = {};
0174 };
0175
0176 }