in kll/include/kll_sketch_impl.hpp [517:597]
kll_sketch<T, C, A> kll_sketch<T, C, A>::deserialize(const void* bytes, size_t size, const SerDe& sd,
const C& comparator, const A& allocator) {
ensure_minimum_memory(size, 8);
const char* ptr = static_cast<const char*>(bytes);
uint8_t preamble_ints;
ptr += copy_from_mem(ptr, preamble_ints);
uint8_t serial_version;
ptr += copy_from_mem(ptr, serial_version);
uint8_t family_id;
ptr += copy_from_mem(ptr, family_id);
uint8_t flags_byte;
ptr += copy_from_mem(ptr, flags_byte);
uint16_t k;
ptr += copy_from_mem(ptr, k);
uint8_t m;
ptr += copy_from_mem(ptr, m);
ptr += sizeof(uint8_t); // skip unused byte
check_m(m);
check_preamble_ints(preamble_ints, flags_byte);
check_serial_version(serial_version);
check_family_id(family_id);
ensure_minimum_memory(size, preamble_ints * sizeof(uint32_t));
const bool is_empty(flags_byte & (1 << flags::IS_EMPTY));
if (is_empty) return kll_sketch(k, comparator, allocator);
uint64_t n;
uint16_t min_k;
uint8_t num_levels;
const bool is_single_item(flags_byte & (1 << flags::IS_SINGLE_ITEM)); // used in serial version 2
const char* end_ptr = static_cast<const char*>(bytes) + size;
if (is_single_item) {
n = 1;
min_k = k;
num_levels = 1;
} else {
ptr += copy_from_mem(ptr, n);
ptr += copy_from_mem(ptr, min_k);
ptr += copy_from_mem(ptr, num_levels);
ptr += sizeof(uint8_t); // skip unused byte
}
vector_u32 levels(num_levels + 1, 0, allocator);
const uint32_t capacity(kll_helper::compute_total_capacity(k, m, num_levels));
if (is_single_item) {
levels[0] = capacity - 1;
} else {
// the last integer in levels_ is not serialized because it can be derived
ptr += copy_from_mem(ptr, levels.data(), sizeof(levels[0]) * num_levels);
}
levels[num_levels] = capacity;
optional<T> tmp; // space to deserialize min and max
optional<T> min_item;
optional<T> max_item;
if (!is_single_item) {
ptr += sd.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
// serde call did not throw, repackage and cleanup
min_item.emplace(*tmp);
(*tmp).~T();
ptr += sd.deserialize(ptr, end_ptr - ptr, &*tmp, 1);
// serde call did not throw, repackage and cleanup
max_item.emplace(*tmp);
(*tmp).~T();
}
A alloc(allocator);
auto items_buffer_deleter = [capacity, &alloc](T* ptr) { alloc.deallocate(ptr, capacity); };
std::unique_ptr<T, decltype(items_buffer_deleter)> items_buffer(alloc.allocate(capacity), items_buffer_deleter);
const auto num_items = levels[num_levels] - levels[0];
ptr += sd.deserialize(ptr, end_ptr - ptr, &items_buffer.get()[levels[0]], num_items);
// serde call did not throw, repackage with destrtuctors
std::unique_ptr<T, items_deleter> items(items_buffer.release(), items_deleter(levels[0], capacity, allocator));
const size_t delta = ptr - static_cast<const char*>(bytes);
if (delta != size) throw std::logic_error("deserialized size mismatch: " + std::to_string(delta) + " != " + std::to_string(size));
const bool is_level_zero_sorted = (flags_byte & (1 << flags::IS_LEVEL_ZERO_SORTED)) > 0;
if (is_single_item) {
min_item.emplace(items.get()[levels[0]]);
max_item.emplace(items.get()[levels[0]]);
}
return kll_sketch(k, min_k, n, num_levels, std::move(levels), std::move(items), capacity,
std::move(min_item), std::move(max_item), is_level_zero_sorted, comparator);
}