in tdigest/include/tdigest_impl.hpp [421:475]
tdigest<T, A> tdigest<T, A>::deserialize(const void* bytes, size_t size, const A& allocator) {
ensure_minimum_memory(size, 8);
const char* ptr = static_cast<const char*>(bytes);
const char* end_ptr = static_cast<const char*>(bytes) + size;
const uint8_t preamble_longs = *ptr++;
const uint8_t serial_version = *ptr++;
const uint8_t sketch_type = *ptr++;
if (sketch_type != SKETCH_TYPE) {
if (preamble_longs == 0 && serial_version == 0 && sketch_type == 0) return deserialize_compat(ptr, end_ptr - ptr, allocator);
throw std::invalid_argument("sketch type mismatch: expected " + std::to_string(SKETCH_TYPE) + ", actual " + std::to_string(sketch_type));
}
if (serial_version != SERIAL_VERSION) {
throw std::invalid_argument("serial version mismatch: expected " + std::to_string(SERIAL_VERSION) + ", actual " + std::to_string(serial_version));
}
uint16_t k;
ptr += copy_from_mem(ptr, k);
const uint8_t flags_byte = *ptr++;
const bool is_empty = flags_byte & (1 << flags::IS_EMPTY);
const bool is_single_value = flags_byte & (1 << flags::IS_SINGLE_VALUE);
const uint8_t expected_preamble_longs = is_empty || is_single_value ? PREAMBLE_LONGS_EMPTY_OR_SINGLE : PREAMBLE_LONGS_MULTIPLE;
if (preamble_longs != expected_preamble_longs) {
throw std::invalid_argument("preamble longs mismatch: expected " + std::to_string(expected_preamble_longs) + ", actual " + std::to_string(preamble_longs));
}
ptr += 2; // unused
if (is_empty) return tdigest(k, allocator);
const bool reverse_merge = flags_byte & (1 << flags::REVERSE_MERGE);
if (is_single_value) {
ensure_minimum_memory(end_ptr - ptr, sizeof(T));
T value;
ptr += copy_from_mem(ptr, value);
return tdigest(reverse_merge, k, value, value, vector_centroid(1, centroid(value, 1), allocator), 1, vector_t(allocator));
}
ensure_minimum_memory(end_ptr - ptr, 8);
uint32_t num_centroids;
ptr += copy_from_mem(ptr, num_centroids);
uint32_t num_buffered;
ptr += copy_from_mem(ptr, num_buffered);
ensure_minimum_memory(end_ptr - ptr, sizeof(T) * 2 + sizeof(centroid) * num_centroids + sizeof(T) * num_buffered);
T min;
ptr += copy_from_mem(ptr, min);
T max;
ptr += copy_from_mem(ptr, max);
vector_centroid centroids(num_centroids, centroid(0, 0), allocator);
if (num_centroids > 0) ptr += copy_from_mem(ptr, centroids.data(), num_centroids * sizeof(centroid));
vector_t buffer(num_buffered, 0, allocator);
if (num_buffered > 0) copy_from_mem(ptr, buffer.data(), num_buffered * sizeof(T));
uint64_t weight = 0;
for (const auto& c: centroids) weight += c.get_weight();
return tdigest(reverse_merge, k, min, max, std::move(centroids), weight, std::move(buffer));
}