/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . Copyright 2017-2019 Telegram Systems LLP */ #pragma once #include #include "td/utils/int_types.h" #include "td/utils/buffer.h" #include "adnl/utils.hpp" #include "validator-session-description.h" namespace ton { namespace validatorsession { using HashType = ValidatorSessionDescription::HashType; template inline HashType get_vs_hash(ValidatorSessionDescription& desc, const T& value) { return value.get_hash(desc); } template inline HashType get_vs_hash(ValidatorSessionDescription& desc, const T* value) { return value ? value->get_hash(desc) : desc.zero_hash(); } HashType get_vector_hash(ValidatorSessionDescription& desc, std::vector&& value); HashType get_pair_hash(ValidatorSessionDescription& desc, const HashType& left, const HashType& right); HashType get_vs_hash(ValidatorSessionDescription& desc, const bool& value); HashType get_vs_hash(ValidatorSessionDescription& desc, const td::uint32& value); HashType get_vs_hash(ValidatorSessionDescription& desc, const td::uint64& value); HashType get_vs_hash(ValidatorSessionDescription& desc, const td::Bits256& value); HashType get_vs_hash(ValidatorSessionDescription& desc, const td::BufferSlice& value); template inline HashType get_vs_hash(ValidatorSessionDescription& desc, const std::pair& value) { return get_pair_hash(desc, get_vs_hash(value.first), get_vs_hash(value.second)); } template inline HashType get_vs_hash(ValidatorSessionDescription& desc, const std::vector& value) { std::vector v; v.resize(value.size()); for (size_t i = 0; i < value.size(); i++) { v[i] = get_vs_hash(desc, value[i]); } return get_vector_hash(desc, std::move(v)); } inline HashType get_vs_hash(ValidatorSessionDescription& desc, const std::vector& value) { std::vector v; v.resize(value.size()); for (size_t i = 0; i < value.size(); i++) { bool b = value[i]; v[i] = get_vs_hash(desc, b); } return get_vector_hash(desc, std::move(v)); } template inline HashType get_vs_hash(ValidatorSessionDescription& desc, td::uint32 size, const T* value) { std::vector v; v.resize(size); for (size_t i = 0; i < size; i++) { v[i] = get_vs_hash(desc, value[i]); } return get_vector_hash(desc, std::move(v)); } inline bool move_to_persistent(ValidatorSessionDescription& desc, bool v) { return v; } inline td::uint32 move_to_persistent(ValidatorSessionDescription& desc, td::uint32 v) { return v; } inline td::uint64 move_to_persistent(ValidatorSessionDescription& desc, td::uint64 v) { return v; } template inline const T* move_to_persistent(ValidatorSessionDescription& desc, const T* v) { return T::move_to_persistent(desc, v); } template class CntVector : public ValidatorSessionDescription::RootObject { public: static HashType create_hash(ValidatorSessionDescription& desc, std::vector& value) { auto obj = create_tl_object(get_vs_hash(desc, value)); return desc.compute_hash(serialize_tl_object(obj, true).as_slice()); } static HashType create_hash(ValidatorSessionDescription& desc, td::uint32 size, const T* value) { auto obj = create_tl_object(get_vs_hash(desc, size, value)); return desc.compute_hash(serialize_tl_object(obj, true).as_slice()); } static bool compare(const RootObject* r, td::uint32 size, const T* data, HashType hash) { if (!r || r->get_size() < sizeof(CntVector)) { return false; } auto R = static_cast(r); if (R->data_size_ != size * sizeof(T) || R->hash_ != hash) { return false; } for (td::uint32 i = 0; i < size; i++) { if (R->data_[i] != data[i]) { return false; } } return true; } static bool compare(const RootObject* r, const std::vector& data, HashType hash) { if (!r || r->get_size() < sizeof(CntVector)) { return false; } auto R = static_cast(r); if (R->data_size_ != sizeof(T) * data.size() || R->hash_ != hash) { return false; } for (td::uint32 i = 0; i < data.size(); i++) { if (R->data_[i] != data[i]) { return false; } } return true; } static const CntVector* lookup(ValidatorSessionDescription& desc, std::vector& value, HashType hash, bool temp) { auto r = desc.get_by_hash(hash, temp); if (compare(r, value, hash)) { desc.on_reuse(); return static_cast(r); } return nullptr; } static const CntVector* lookup(ValidatorSessionDescription& desc, td::uint32 size, const T* data, HashType hash, bool temp) { auto r = desc.get_by_hash(hash, temp); if (compare(r, size, data, hash)) { desc.on_reuse(); return static_cast(r); } return nullptr; } static const CntVector* create(ValidatorSessionDescription& desc, std::vector value) { if (value.size() == 0) { return nullptr; } auto hash = create_hash(desc, value); auto r = lookup(desc, value, hash, true); if (r) { return r; } auto size = static_cast(value.size()); auto data = static_cast(desc.alloc(sizeof(T) * size, 8, true)); for (td::uint32 i = 0; i < size; i++) { data[i] = value[i]; } return new (desc, true) CntVector{desc, size, data, hash}; } static const CntVector* create(ValidatorSessionDescription& desc, td::uint32 size, const T* value) { if (!size) { return nullptr; } auto hash = create_hash(desc, size, value); auto r = lookup(desc, size, value, hash, true); if (r) { return r; } return new (desc, true) CntVector{desc, size, value, hash}; } static const CntVector* move_to_persistent(ValidatorSessionDescription& desc, const CntVector* b) { if (desc.is_persistent(b)) { return b; } std::vector v; v.resize(b->size()); for (td::uint32 i = 0; i < b->size(); i++) { v[i] = ton::validatorsession::move_to_persistent(desc, b->data_[i]); } auto r = lookup(desc, v, b->hash_, false); if (r) { return r; } auto data = static_cast(desc.alloc(sizeof(T) * b->size(), 8, false)); for (td::uint32 i = 0; i < b->size(); i++) { data[i] = v[i]; } return new (desc, false) CntVector{desc, b->size(), data, b->hash_}; } static const CntVector* merge(ValidatorSessionDescription& desc, const CntVector* l, const CntVector* r, std::function merge_f, bool merge_all = false) { if (!merge_all) { if (!l) { return r; } if (!r) { return l; } if (l == r) { return l; } } auto sz = std::max(l->size(), r->size()); bool ret_left = true; bool ret_right = true; for (td::uint32 i = 0; i < sz; i++) { if (i >= l->size()) { ret_left = false; break; } else if (i >= r->size()) { ret_right = false; break; } else if (l->at(i) != r->at(i)) { if (l->at(i)) { ret_right = false; } if (r->at(i)) { ret_left = false; } } } if (!merge_all && ret_left) { return l; } if (!merge_all && ret_right) { return r; } auto v = static_cast(desc.alloc(sizeof(T) * sz, 8, true)); for (td::uint32 i = 0; i < sz; i++) { if (i >= l->size()) { if (!merge_all) { v[i] = r->at(i); } else { v[i] = merge_f(r->at(i), r->at(i)); } } else if (i >= r->size()) { if (!merge_all) { v[i] = l->at(i); } else { v[i] = merge_f(l->at(i), l->at(i)); } } else { v[i] = merge_f(l->at(i), r->at(i)); } } return create(desc, sz, v); } static const CntVector* modify(ValidatorSessionDescription& desc, const CntVector* l, std::function mod_f) { if (!l) { return l; } auto sz = l->size(); auto v = static_cast(desc.alloc(sizeof(T) * sz, 8, true)); for (td::uint32 i = 0; i < sz; i++) { v[i] = mod_f(l->at(i)); } return create(desc, sz, v); } static const CntVector* change(ValidatorSessionDescription& desc, const CntVector* l, td::uint32 idx, T value) { auto sz = l->size(); auto v = static_cast(desc.alloc(sizeof(T) * sz, 8, true)); std::memcpy(v, l->data_, sizeof(T) * sz); v[idx] = std::move(value); return create(desc, sz, v); } static const CntVector* push(ValidatorSessionDescription& desc, const CntVector* l, td::uint32 idx, T value) { td::uint32 sz = l ? l->size() : 0; CHECK(idx == sz); sz++; auto v = static_cast(desc.alloc(sizeof(T) * sz, 8, true)); if (l) { std::memcpy(v, l->data_, sizeof(T) * (sz - 1)); } v[idx] = std::move(value); return create(desc, sz, v); } CntVector(ValidatorSessionDescription& desc, td::uint32 data_size, const T* data, HashType hash) : RootObject{sizeof(CntVector)} , data_size_(static_cast(data_size * sizeof(T))) , data_(data) , hash_(std::move(hash)) { desc.update_hash(this, hash_); } td::uint32 size() const { return static_cast(data_size_ / sizeof(T)); } auto data() const { return data_; } auto get_hash(ValidatorSessionDescription& desc) const { return hash_; } T at(td::uint32 idx) const { CHECK(idx < size()); return data_[idx]; } //const T& at(size_t idx) const; private: const td::uint32 data_size_; const T* data_; const HashType hash_; }; template <> class CntVector : public ValidatorSessionDescription::RootObject { private: static bool get_bit(const td::uint32* value, td::uint32 idx) { return (value[idx / 32] & (1u << (idx % 32))) != 0; } static void set_bit(td::uint32* value, td::uint32 idx, bool v) { if (v) { value[idx / 32] |= (1u << (idx % 32)); } else { value[idx / 32] &= ~static_cast((1u << (idx % 32))); } } public: static HashType create_hash(ValidatorSessionDescription& desc, std::vector& value) { CHECK(value.size() % 32 == 0); auto b = new td::uint32[value.size() / 32]; for (td::uint32 i = 0; i < value.size(); i++) { set_bit(b, i, value[i]); } auto hash = create_hash(desc, static_cast(value.size()), b); delete[] b; return hash; } static HashType create_hash(ValidatorSessionDescription& desc, td::uint32 size, const td::uint32* value) { return desc.compute_hash(td::Slice(reinterpret_cast(value), size / 8)); } static bool compare(const RootObject* r, td::uint32 size, const td::uint32* data, HashType hash) { CHECK(size % 32 == 0); if (!r || r->get_size() < sizeof(CntVector)) { return false; } auto R = static_cast(r); if (R->data_size_ != size / 8 || R->hash_ != hash) { return false; } return std::memcmp(R->data_, data, size / 8) == 0; } static bool compare(const RootObject* r, const std::vector& data, HashType hash) { CHECK(data.size() % 32 == 0); if (!r || r->get_size() < sizeof(CntVector)) { return false; } auto R = static_cast(r); if (R->data_size_ != data.size() / 8 || R->hash_ != hash) { return false; } for (td::uint32 i = 0; i < data.size(); i++) { if (get_bit(R->data_, i) != data[i]) { return false; } } return true; } static const CntVector* lookup(ValidatorSessionDescription& desc, std::vector& value, HashType hash, bool temp) { CHECK(value.size() % 32 == 0); auto r = desc.get_by_hash(hash, temp); if (compare(r, value, hash)) { desc.on_reuse(); return static_cast(r); } return nullptr; } static const CntVector* lookup(ValidatorSessionDescription& desc, td::uint32 size, const td::uint32* data, HashType hash, bool temp) { CHECK(size % 32 == 0); auto r = desc.get_by_hash(hash, temp); if (compare(r, size, data, hash)) { desc.on_reuse(); return static_cast(r); } return nullptr; } static const CntVector* create(ValidatorSessionDescription& desc, std::vector value) { if (value.size() == 0) { return nullptr; } if (value.size() % 32) { auto new_size = value.size() - value.size() % 32 + 32; value.resize(new_size, false); } auto hash = create_hash(desc, value); auto r = lookup(desc, value, hash, true); if (r) { return r; } auto size = static_cast(value.size()); auto data = static_cast(desc.alloc(sizeof(td::uint32) * size / 32, 8, true)); for (td::uint32 i = 0; i < size; i++) { set_bit(data, i, value[i]); } return new (desc, true) CntVector{desc, size, data, hash}; } static const CntVector* create(ValidatorSessionDescription& desc, td::uint32 size, const td::uint32* value) { if (!size) { return nullptr; } CHECK(size % 32 == 0); auto hash = create_hash(desc, size, value); auto r = lookup(desc, size, value, hash, true); if (r) { return r; } return new (desc, true) CntVector{desc, size, value, hash}; } static const CntVector* move_to_persistent(ValidatorSessionDescription& desc, const CntVector* b) { if (desc.is_persistent(b)) { return b; } auto r = lookup(desc, b->max_size(), b->data_, b->hash_, false); if (r) { return r; } auto data = static_cast(desc.alloc(b->data_size_, 8, false)); std::memcpy(data, b->data_, b->data_size_); return new (desc, false) CntVector{desc, b->max_size(), data, b->hash_}; } static const CntVector* merge(ValidatorSessionDescription& desc, const CntVector* l, const CntVector* r) { if (!l) { return r; } if (!r) { return l; } if (l == r) { return l; } CHECK(l->max_size() == r->max_size()); auto sz = l->max_size() / 32; bool ret_left = true; bool ret_right = true; for (td::uint32 i = 0; i < sz; i++) { if (l->data_[i] & ~r->data_[i]) { ret_right = false; } if (r->data_[i] & ~l->data_[i]) { ret_left = false; } } if (ret_left) { return l; } if (ret_right) { return r; } auto v = static_cast(desc.alloc(sz * 4, 8, true)); for (td::uint32 i = 0; i < sz; i++) { v[i] = l->data_[i] | r->data_[i]; } return create(desc, sz * 32, v); } static const CntVector* merge(ValidatorSessionDescription& desc, const CntVector* l, const CntVector* r, std::function merge_f) { if (!l) { return r; } if (!r) { return l; } if (l == r) { return l; } auto sz = std::max(l->max_size(), r->max_size()); auto v = static_cast(desc.alloc(sz / 8, 8, true)); std::memset(v, 0, sz / 8); for (td::uint32 i = 0; i < sz; i++) { if (i >= l->max_size()) { set_bit(v, i, r->at(i)); } else if (i >= r->max_size()) { set_bit(v, i, l->at(i)); } else { set_bit(v, i, merge_f(l->at(i), r->at(i))); } } return create(desc, sz, v); } static const CntVector* change(ValidatorSessionDescription& desc, const CntVector* l, td::uint32 idx, bool value) { if (l->at(idx) == value) { return l; } auto sz = l->max_size(); auto v = static_cast(desc.alloc(sz / 8, 8, true)); std::memcpy(v, l->data_, l->data_size_); set_bit(v, idx, value); return create(desc, sz, v); } CntVector(ValidatorSessionDescription& desc, td::uint32 data_size, const td::uint32* data, HashType hash) : RootObject{sizeof(CntVector)} , data_size_(static_cast(data_size / 8)) , data_(data) , hash_(std::move(hash)) { desc.update_hash(this, hash_); CHECK(data_size % 32 == 0); } td::uint32 max_size() const { return data_size_ * 8; } auto data() const { return data_; } auto get_hash(ValidatorSessionDescription& desc) const { return hash_; } bool at(td::uint32 idx) const { CHECK(idx < max_size()); return get_bit(data_, idx); } //const T& at(size_t idx) const; private: const td::uint32 data_size_; const td::uint32* data_; const HashType hash_; }; template > class CntSortedVector : public ValidatorSessionDescription::RootObject { public: static HashType create_hash(ValidatorSessionDescription& desc, std::vector& value) { auto obj = create_tl_object(get_vs_hash(desc, value)); return desc.compute_hash(serialize_tl_object(obj, true).as_slice()); } static HashType create_hash(ValidatorSessionDescription& desc, td::uint32 size, const T* value) { auto obj = create_tl_object(get_vs_hash(desc, size, value)); return desc.compute_hash(serialize_tl_object(obj, true).as_slice()); } static bool compare(const RootObject* r, td::uint32 size, const T* data, HashType hash) { if (!r || r->get_size() < sizeof(CntSortedVector)) { return false; } auto R = static_cast(r); if (R->data_size_ != size * sizeof(T) || R->hash_ != hash) { return false; } for (td::uint32 i = 0; i < size; i++) { if (R->data_[i] != data[i]) { return false; } } return true; } static bool compare(const RootObject* r, const std::vector& data, HashType hash) { if (!r || r->get_size() < sizeof(CntSortedVector)) { return false; } auto R = static_cast(r); if (R->data_size_ != data.size() * sizeof(T) || R->hash_ != hash) { return false; } for (td::uint32 i = 0; i < data.size(); i++) { if (R->data_[i] != data[i]) { return false; } } return true; } static const CntSortedVector* lookup(ValidatorSessionDescription& desc, std::vector& value, HashType hash, bool temp) { auto r = desc.get_by_hash(hash, temp); if (compare(r, value, hash)) { desc.on_reuse(); return static_cast(r); } return nullptr; } static const CntSortedVector* lookup(ValidatorSessionDescription& desc, td::uint32 size, const T* data, HashType hash, bool temp) { auto r = desc.get_by_hash(hash, temp); if (compare(r, size, data, hash)) { desc.on_reuse(); return static_cast(r); } return nullptr; } static const CntSortedVector* create(ValidatorSessionDescription& desc, std::vector value) { if (value.size() == 0) { return nullptr; } auto hash = create_hash(desc, value); auto r = lookup(desc, value, hash, true); if (r) { return r; } auto data_size = static_cast(value.size()); auto data = static_cast(desc.alloc(sizeof(T) * data_size, 8, true)); for (td::uint32 i = 0; i < data_size; i++) { data[i] = value[i]; } return new (desc, true) CntSortedVector{desc, data_size, data, hash}; } static const CntSortedVector* create(ValidatorSessionDescription& desc, td::uint32 size, const T* value) { if (size == 0) { return nullptr; } auto hash = create_hash(desc, size, value); auto r = lookup(desc, size, value, hash, true); if (r) { return r; } return new (desc, true) CntSortedVector{desc, size, value, hash}; } static const CntSortedVector* move_to_persistent(ValidatorSessionDescription& desc, const CntSortedVector* b) { if (desc.is_persistent(b)) { return b; } std::vector v; v.resize(b->size()); for (td::uint32 i = 0; i < v.size(); i++) { v[i] = ton::validatorsession::move_to_persistent(desc, b->data_[i]); } auto r = lookup(desc, v, b->hash_, false); if (r) { return r; } auto data = static_cast(desc.alloc(sizeof(T) * v.size(), 8, false)); for (td::uint32 i = 0; i < v.size(); i++) { data[i] = v[i]; } return new (desc, false) CntSortedVector{desc, b->size(), data, b->hash_}; } static const CntSortedVector* merge(ValidatorSessionDescription& desc, const CntSortedVector* l, const CntSortedVector* r, std::function merge_f) { if (!l) { return r; } if (!r) { return l; } if (l == r) { return l; } bool ret_left = true; bool ret_right = true; const T* li = l->data_; const T* ri = r->data_; td::uint32 lp = 0; td::uint32 rp = 0; while (lp < l->size() || rp < r->size()) { if (lp == l->size()) { ret_left = false; break; } else if (rp == r->size()) { ret_right = false; break; } else { if (Compare()(li[lp], ri[rp])) { ret_right = false; lp++; } else if (Compare()(ri[rp], li[lp])) { ret_left = false; rp++; } else { if (li[lp++] != ri[rp++]) { ret_left = false; ret_right = false; break; } } } } if (ret_left) { return l; } if (ret_right) { return r; } std::vector v; lp = 0; rp = 0; while (lp < l->size() || rp < r->size()) { if (lp == l->size()) { v.push_back(ri[rp++]); } else if (rp == r->size()) { v.push_back(li[lp++]); } else { if (Compare()(li[lp], ri[rp])) { v.push_back(li[lp++]); } else if (Compare()(ri[rp], li[lp])) { v.push_back(ri[rp++]); } else { v.push_back(merge_f(li[lp++], ri[rp++])); } } } return CntSortedVector::create(desc, std::move(v)); } /*static const CntSortedVector* merge(ValidatorSessionDescription& desc, const CntSortedVector* l, const CntSortedVector* r) { return merge(desc, l, r, [](T l, T r) { return l; }); }*/ static const CntSortedVector* push(ValidatorSessionDescription& desc, const CntSortedVector* v, T value) { if (!v) { return create(desc, std::vector{value}); } T* res = nullptr; td::uint32 res_size = 0; td::int32 l = -1; td::int32 r = v->size(); bool found = false; while (r - l > 1) { auto x = (r + l) / 2; if (Compare()(v->at(x), value)) { l = x; } else if (Compare()(value, v->at(x))) { r = x; } else { if (v->at(x) == value) { return v; } res = static_cast(desc.alloc(sizeof(T) * v->size(), 8, true)); std::memcpy(res, v->data(), sizeof(T) * v->size()); res[x] = value; res_size = v->size(); found = true; break; } } if (!found) { res = static_cast(desc.alloc(sizeof(T) * (v->size() + 1), 8, true)); res_size = v->size() + 1; std::memcpy(res, v->data(), sizeof(T) * r); res[r] = value; std::memcpy(res + r + 1, v->data() + r, sizeof(T) * (v->size() - r)); } return CntSortedVector::create(desc, res_size, res); } CntSortedVector(ValidatorSessionDescription& desc, td::uint32 data_size, const T* data, HashType hash) : RootObject{sizeof(CntSortedVector)} , data_size_(static_cast(data_size * sizeof(T))) , data_(data) , hash_(std::move(hash)) { desc.update_hash(this, hash_); } td::uint32 size() const { return static_cast(data_size_ / sizeof(T)); } auto data() const { return data_; } auto get_hash(ValidatorSessionDescription& desc) const { return hash_; } T at(td::uint32 idx) const { CHECK(idx < size()); return data_[idx]; } //const T& at(size_t idx) const; private: const td::uint32 data_size_; const T* data_; const HashType hash_; }; } // namespace validatorsession } // namespace ton