tdigest tdigest::deserialize_compat()

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));
}