mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			808 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			808 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
    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 <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
    Copyright 2017-2020 Telegram Systems LLP
 | 
						|
*/
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include <functional>
 | 
						|
 | 
						|
#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 <class T>
 | 
						|
inline HashType get_vs_hash(ValidatorSessionDescription& desc, const T& value) {
 | 
						|
  return value.get_hash(desc);
 | 
						|
}
 | 
						|
 | 
						|
template <class T>
 | 
						|
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<HashType>&& 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 <typename T1, typename T2>
 | 
						|
inline HashType get_vs_hash(ValidatorSessionDescription& desc, const std::pair<T1, T2>& value) {
 | 
						|
  return get_pair_hash(desc, get_vs_hash(value.first), get_vs_hash(value.second));
 | 
						|
}
 | 
						|
 | 
						|
template <typename T>
 | 
						|
inline HashType get_vs_hash(ValidatorSessionDescription& desc, const std::vector<T>& value) {
 | 
						|
  std::vector<HashType> 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<bool>& value) {
 | 
						|
  std::vector<HashType> 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 <typename T>
 | 
						|
inline HashType get_vs_hash(ValidatorSessionDescription& desc, td::uint32 size, const T* value) {
 | 
						|
  std::vector<HashType> 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 <typename T>
 | 
						|
inline const T* move_to_persistent(ValidatorSessionDescription& desc, const T* v) {
 | 
						|
  return T::move_to_persistent(desc, v);
 | 
						|
}
 | 
						|
 | 
						|
template <typename T>
 | 
						|
class CntVector : public ValidatorSessionDescription::RootObject {
 | 
						|
 public:
 | 
						|
  static HashType create_hash(ValidatorSessionDescription& desc, std::vector<T>& value) {
 | 
						|
    auto obj = create_tl_object<ton_api::hashable_cntVector>(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<ton_api::hashable_cntVector>(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<const CntVector*>(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<T>& data, HashType hash) {
 | 
						|
    if (!r || r->get_size() < sizeof(CntVector)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    auto R = static_cast<const CntVector*>(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<T>& value, HashType hash, bool temp) {
 | 
						|
    auto r = desc.get_by_hash(hash, temp);
 | 
						|
    if (compare(r, value, hash)) {
 | 
						|
      desc.on_reuse();
 | 
						|
      return static_cast<const CntVector*>(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<const CntVector*>(r);
 | 
						|
    }
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  static const CntVector* create(ValidatorSessionDescription& desc, std::vector<T> 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<td::uint32>(value.size());
 | 
						|
    auto data = static_cast<T*>(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<T> 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<T*>(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<T(T, T)> 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<T*>(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<T(T)> mod_f) {
 | 
						|
    if (!l) {
 | 
						|
      return l;
 | 
						|
    }
 | 
						|
    auto sz = l->size();
 | 
						|
 | 
						|
    auto v = static_cast<T*>(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<T*>(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<T*>(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<td::uint32>(data_size * sizeof(T)))
 | 
						|
      , data_(data)
 | 
						|
      , hash_(std::move(hash)) {
 | 
						|
    desc.update_hash(this, hash_);
 | 
						|
  }
 | 
						|
  td::uint32 size() const {
 | 
						|
    return static_cast<td::uint32>(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<bool> : 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<td::uint32>((1u << (idx % 32)));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 public:
 | 
						|
  static HashType create_hash(ValidatorSessionDescription& desc, std::vector<bool>& 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<td::uint32>(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<const td::uint8*>(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<const CntVector*>(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<bool>& data, HashType hash) {
 | 
						|
    CHECK(data.size() % 32 == 0);
 | 
						|
    if (!r || r->get_size() < sizeof(CntVector)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    auto R = static_cast<const CntVector*>(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<bool>& 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<const CntVector*>(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<const CntVector*>(r);
 | 
						|
    }
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  static const CntVector* create(ValidatorSessionDescription& desc, std::vector<bool> 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<td::uint32>(value.size());
 | 
						|
    auto data = static_cast<td::uint32*>(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<td::uint32*>(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<td::uint32*>(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<bool(bool, bool)> 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<td::uint32*>(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<td::uint32*>(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<td::uint32>(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 <typename T, typename Compare = std::less<T>>
 | 
						|
class CntSortedVector : public ValidatorSessionDescription::RootObject {
 | 
						|
 public:
 | 
						|
  static HashType create_hash(ValidatorSessionDescription& desc, std::vector<T>& value) {
 | 
						|
    auto obj = create_tl_object<ton_api::hashable_cntSortedVector>(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<ton_api::hashable_cntSortedVector>(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<const CntSortedVector*>(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<T>& data, HashType hash) {
 | 
						|
    if (!r || r->get_size() < sizeof(CntSortedVector)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    auto R = static_cast<const CntSortedVector*>(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<T>& value, HashType hash,
 | 
						|
                                       bool temp) {
 | 
						|
    auto r = desc.get_by_hash(hash, temp);
 | 
						|
    if (compare(r, value, hash)) {
 | 
						|
      desc.on_reuse();
 | 
						|
      return static_cast<const CntSortedVector*>(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<const CntSortedVector*>(r);
 | 
						|
    }
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  static const CntSortedVector* create(ValidatorSessionDescription& desc, std::vector<T> 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<td::uint32>(value.size());
 | 
						|
    auto data = static_cast<T*>(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<T> 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<T*>(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<T(T, T)> 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<T> 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<T>{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<T*>(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<T*>(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<td::uint32>(data_size * sizeof(T)))
 | 
						|
      , data_(data)
 | 
						|
      , hash_(std::move(hash)) {
 | 
						|
    desc.update_hash(this, hash_);
 | 
						|
  }
 | 
						|
  td::uint32 size() const {
 | 
						|
    return static_cast<td::int32>(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
 |