in kll/include/kll_sketch_impl.hpp [672:723]
void kll_sketch<T, C, A>::compress_while_updating(void) {
const uint8_t level = find_level_to_compact();
// It is important to add the new top level right here. Be aware that this operation
// grows the buffer and shifts the data and also the boundaries of the data and grows the
// levels array and increments num_levels_
if (level == (num_levels_ - 1)) {
add_empty_top_level_to_completely_full_sketch();
}
const uint32_t raw_beg = levels_[level];
const uint32_t raw_lim = levels_[level + 1];
// +2 is OK because we already added a new top level if necessary
const uint32_t pop_above = levels_[level + 2] - raw_lim;
const uint32_t raw_pop = raw_lim - raw_beg;
const bool odd_pop = kll_helper::is_odd(raw_pop);
const uint32_t adj_beg = odd_pop ? raw_beg + 1 : raw_beg;
const uint32_t adj_pop = odd_pop ? raw_pop - 1 : raw_pop;
const uint32_t half_adj_pop = adj_pop / 2;
const uint32_t destroy_beg = levels_[0];
// level zero might not be sorted, so we must sort it if we wish to compact it
// sort_level_zero() is not used here because of the adjustment for odd number of items
if ((level == 0) && !is_level_zero_sorted_) {
std::sort(items_ + adj_beg, items_ + adj_beg + adj_pop, comparator_);
}
if (pop_above == 0) {
kll_helper::randomly_halve_up(items_, adj_beg, adj_pop);
} else {
kll_helper::randomly_halve_down(items_, adj_beg, adj_pop);
kll_helper::merge_sorted_arrays<T, C>(items_, adj_beg, half_adj_pop, raw_lim, pop_above, adj_beg + half_adj_pop);
}
levels_[level + 1] -= half_adj_pop; // adjust boundaries of the level above
if (odd_pop) {
levels_[level] = levels_[level + 1] - 1; // the current level now contains one item
if (levels_[level] != raw_beg) items_[levels_[level]] = std::move(items_[raw_beg]); // namely this leftover guy
} else {
levels_[level] = levels_[level + 1]; // the current level is now empty
}
// verify that we freed up half_adj_pop array slots just below the current level
if (levels_[level] != (raw_beg + half_adj_pop)) throw std::logic_error("compaction error");
// finally, we need to shift up the data in the levels below
// so that the freed-up space can be used by level zero
if (level > 0) {
const uint32_t amount = raw_beg - levels_[0];
std::move_backward(items_ + levels_[0], items_ + levels_[0] + amount, items_ + levels_[0] + half_adj_pop + amount);
for (uint8_t lvl = 0; lvl < level; lvl++) levels_[lvl] += half_adj_pop;
}
for (uint32_t i = 0; i < half_adj_pop; i++) items_[i + destroy_beg].~T();
}