in tdigest/include/tdigest_impl.hpp [524:593]
tdigest<T, A> tdigest<T, A>::deserialize_compat(const void* bytes, size_t size, const A& allocator) {
const char* ptr = static_cast<const char*>(bytes);
// this method was called because the first three bytes were zeros
// so read one more byte to see if it looks like the reference implementation format
const auto type = *ptr++;
if (type != COMPAT_DOUBLE && type != COMPAT_FLOAT) {
throw std::invalid_argument("unexpected sketch preamble: 0 0 0 " + std::to_string(type));
}
const char* end_ptr = static_cast<const char*>(bytes) + size;
if (type == COMPAT_DOUBLE) { // compatibility with asBytes()
ensure_minimum_memory(end_ptr - ptr, sizeof(double) * 3 + sizeof(uint32_t));
double min;
ptr += copy_from_mem(ptr, min);
min = byteswap(min);
double max;
ptr += copy_from_mem(ptr, max);
max = byteswap(max);
double k_double;
ptr += copy_from_mem(ptr, k_double);
const uint16_t k = static_cast<uint16_t>(byteswap(k_double));
uint32_t num_centroids;
ptr += copy_from_mem(ptr, num_centroids);
num_centroids = byteswap(num_centroids);
ensure_minimum_memory(end_ptr - ptr, sizeof(double) * num_centroids * 2);
vector_centroid centroids(num_centroids, centroid(0, 0), allocator);
uint64_t total_weight = 0;
for (auto& c: centroids) {
double weight;
ptr += copy_from_mem(ptr, weight);
weight = byteswap(weight);
double mean;
ptr += copy_from_mem(ptr, mean);
mean = byteswap(mean);
c = centroid(mean, static_cast<W>(weight));
total_weight += static_cast<uint64_t>(weight);
}
return tdigest(false, k, min, max, std::move(centroids), total_weight, vector_t(allocator));
}
// COMPAT_FLOAT: compatibility with asSmallBytes()
ensure_minimum_memory(end_ptr - ptr, sizeof(double) * 2 + sizeof(float) + sizeof(uint16_t) * 3);
double min; // reference implementation uses doubles for min and max
ptr += copy_from_mem(ptr, min);
min = byteswap(min);
double max;
ptr += copy_from_mem(ptr, max);
max = byteswap(max);
float k_float;
ptr += copy_from_mem(ptr, k_float);
const uint16_t k = static_cast<uint16_t>(byteswap(k_float));
// reference implementation stores capacities of the array of centroids and the buffer as shorts
// they can be derived from k in the constructor
ptr += sizeof(uint32_t); // unused
uint16_t num_centroids;
ptr += copy_from_mem(ptr, num_centroids);
num_centroids = byteswap(num_centroids);
ensure_minimum_memory(end_ptr - ptr, sizeof(float) * num_centroids * 2);
vector_centroid centroids(num_centroids, centroid(0, 0), allocator);
uint64_t total_weight = 0;
for (auto& c: centroids) {
float weight;
ptr += copy_from_mem(ptr, weight);
weight = byteswap(weight);
float mean;
ptr += copy_from_mem(ptr, mean);
mean = byteswap(mean);
c = centroid(mean, static_cast<W>(weight));
total_weight += static_cast<uint64_t>(weight);
}
return tdigest(false, k, min, max, std::move(centroids), total_weight, vector_t(allocator));
}