11 #ifndef TLX_CONTAINER_RADIX_HEAP_HEADER 12 #define TLX_CONTAINER_RADIX_HEAP_HEADER 17 #include <type_traits> 28 namespace radix_heap_detail {
40 template <
typename Int>
44 "SignedInt has to be an integral type");
48 using rank_type =
typename std::make_unsigned<int_type>::type;
74 "Rank of minimum is not zero");
76 "Rank of minimum+1 is not one");
79 "Rank of maximum is not maximum rank");
82 "Rank of maximum is not larger than rank of zero");
89 template <
size_t Size,
bool SizeIsAtmost64>
92 template <
size_t Size>
95 static constexpr
size_t leaf_width = 6;
97 static_assert(width > leaf_width,
98 "Size has to be larger than 2**leaf_width");
99 static constexpr
size_t root_width = (width % leaf_width)
100 ? (width % leaf_width)
102 static constexpr
size_t child_width = width - root_width;
105 static constexpr
size_t root_size =
div_ceil(Size, child_type::size);
111 static constexpr
size_t size = Size;
119 void set_bit(const
size_t i) {
120 const auto idx = get_index_(i);
121 root_.set_bit(idx.first);
122 children_[idx.first].set_bit(idx.second);
126 const auto idx = get_index_(i);
127 children_[idx.first].clear_bit(idx.second);
128 if (children_[idx.first].empty())
129 root_.clear_bit(idx.first);
133 const auto idx = get_index_(i);
134 return children_[idx.first].is_set(idx.second);
139 for (
auto& child : children_)
144 return root_.empty();
150 const size_t child_idx = root_.find_lsb();
151 const size_t child_val = children_[child_idx].find_lsb();
153 return child_idx * child_type::size + child_val;
162 return { i / child_type::size, i % child_type::size };
166 template <
size_t Size>
169 static_assert(Size <= 64,
"Support at most 64 bits");
170 using uint_type =
typename std::conditional<
171 Size <= 32, uint32_t, uint64_t>::type;
174 static constexpr
size_t size = Size;
194 return (flags_ & (
uint_type(1) << i)) != 0;
224 template <
size_t Size>
230 static constexpr
size_t size = Size;
232 explicit BitArray() noexcept = default;
239 void set_bit(const
size_t i) {
250 return impl_.is_set(i);
260 return impl_.empty();
266 return impl_.find_lsb();
273 template <
unsigned Radix,
typename Int>
281 size_t operator () (
const Int
x,
const Int insertion_limit)
const {
282 constexpr Int mask = (1u << radix_bits) - 1;
284 assert(x >= insertion_limit);
286 const auto diff = x ^ insertion_limit;
289 const auto diff_in_bit = (8 *
sizeof(Int) - 1) -
clz(diff);
291 const auto row = diff_in_bit / radix_bits;
292 const auto bucket_in_row = ((x >> (radix_bits * row)) & mask) - row;
294 const auto result = row * Radix + bucket_in_row;
301 assert(idx < num_buckets);
304 return static_cast<Int
>(idx);
306 const size_t row = (idx - 1) / (Radix - 1);
307 const auto digit =
static_cast<Int
>(idx - row * (Radix - 1));
309 return digit << radix_bits * row;
314 assert(idx < num_buckets);
316 if (idx == num_buckets - 1)
319 return lower_bound(idx + 1) - 1;
324 return (bits >= radix_bits)
325 ? (Radix - 1) + num_buckets_(bits - radix_bits)
331 static constexpr
size_t num_buckets =
336 template <
typename KeyType,
typename DataType>
340 KeyType operator () (
const std::pair<KeyType, DataType>& p)
const {
374 template <
typename ValueType,
typename KeyExtract,
375 typename KeyType,
unsigned Radix = 8>
379 "Radix has to be power of two");
381 static constexpr
bool debug =
false;
388 static constexpr
unsigned radix = Radix;
397 static constexpr
unsigned num_layers =
399 static constexpr
unsigned num_buckets = bucket_map_type::num_buckets;
404 explicit RadixHeap(KeyExtract key_extract = KeyExtract { })
405 : key_extract_(key_extract) {
418 return get_bucket_key(key_extract_(value));
422 const auto enc = Encoder::rank_of_int(key);
423 assert(enc >= insertion_limit_);
425 return bucket_map_(enc, insertion_limit_);
432 template <
typename... Args>
434 const auto enc = Encoder::rank_of_int(key);
435 assert(enc >= insertion_limit_);
436 const auto idx = bucket_map_(enc, insertion_limit_);
438 emplace_in_bucket(idx, std::forward<Args>(args) ...);
444 template <
typename... Args>
446 return emplace(key, key, std::forward<Args>(args) ...);
453 template <
typename... Args>
455 if (buckets_data_[idx].empty()) filled_.set_bit(idx);
456 buckets_data_[idx].emplace_back(std::forward<Args>(args) ...);
458 const auto enc = Encoder::rank_of_int(
459 key_extract_(buckets_data_[idx].back()));
460 if (mins_[idx] > enc) mins_[idx] = enc;
461 assert(idx == bucket_map_(enc, insertion_limit_));
468 const auto enc = Encoder::rank_of_int(key_extract_(value));
469 assert(enc >= insertion_limit_);
471 const auto idx = bucket_map_(enc, insertion_limit_);
473 push_to_bucket(idx, value);
483 const auto enc = Encoder::rank_of_int(key_extract_(value));
485 assert(enc >= insertion_limit_);
486 assert(idx == get_bucket(value));
488 if (buckets_data_[idx].empty()) filled_.set_bit(idx);
489 buckets_data_[idx].push_back(value);
491 if (mins_[idx] > enc) mins_[idx] = enc;
509 const auto first = filled_.find_lsb();
510 return Encoder::int_at_rank(mins_[first]);
517 return buckets_data_[current_bucket_].back();
524 buckets_data_[current_bucket_].pop_back();
525 if (buckets_data_[current_bucket_].empty())
526 filled_.clear_bit(current_bucket_);
537 assert(exchange_bucket.empty());
538 size_ -= buckets_data_[current_bucket_].size();
539 buckets_data_[current_bucket_].swap(exchange_bucket);
541 filled_.clear_bit(current_bucket_);
546 for (
auto&
x : buckets_data_)
x.clear();
554 size_t current_bucket_{ 0 };
560 std::array<ranked_key_type, num_buckets>
mins_;
568 std::fill(mins_.begin(), mins_.end(),
578 if (
TLX_LIKELY(!buckets_data_[current_bucket_].empty())) {
579 assert(current_bucket_ < Radix);
588 const auto first_non_empty = filled_.
find_lsb();
591 assert(first_non_empty < num_buckets);
593 for (
size_t i = 0; i < first_non_empty; i++) {
594 assert(buckets_data_[i].empty());
598 assert(!buckets_data_[first_non_empty].empty());
605 current_bucket_ = first_non_empty;
611 const auto new_ins_limit = mins_[first_non_empty];
612 assert(new_ins_limit > insertion_limit_);
613 insertion_limit_ = new_ins_limit;
616 auto& data_source = buckets_data_[first_non_empty];
618 for (
auto&
x : data_source) {
620 assert(key >= mins_[first_non_empty]);
621 assert(first_non_empty == mins_.size() - 1
622 || key < mins_[first_non_empty + 1]);
623 const auto idx = bucket_map_(key, insertion_limit_);
624 assert(idx < first_non_empty);
627 if (buckets_data_[idx].empty()) filled_.
set_bit(idx);
628 buckets_data_[idx].push_back(std::move(
x));
629 if (mins_[idx] > key) mins_[idx] = key;
639 current_bucket_ = filled_.
find_lsb();
640 assert(current_bucket_ < Radix);
641 assert(!buckets_data_[current_bucket_].empty());
642 assert(mins_[current_bucket_] >= insertion_limit_);
650 template <
typename DataType,
unsigned Radix = 8,
typename KeyExtract =
void>
652 RadixHeap<DataType, KeyExtract,
653 decltype(key_extract(std::declval<DataType>())), Radix> {
656 decltype(key_extract(DataType{ })), Radix > {
666 template <
typename KeyType,
typename DataType,
unsigned Radix = 8>
668 std::pair<KeyType, DataType>,
677 #endif // !TLX_CONTAINER_RADIX_HEAP_HEADER typename Encoder::rank_type ranked_key_type
static uint_pair max()
return an uint_pair instance containing the largest value possible
Int lower_bound(const size_t idx) const
Return smallest key possible in bucket idx assuming insertion_limit==0.
size_t size() const
Returns number of elements currently stored.
bucket_index_type emplace_keyfirst(const key_type key, Args &&... args)
static unsigned ffs(int i)
find first set bit in integer, or zero if none are set.
bool empty() const
Indicates whether size() == 0.
static constexpr int_type int_at_rank(rank_type r)
typename std::make_unsigned< int_type >::type rank_type
key_type peak_top_key() const
Returns currently smallest key without updating the insertion limit.
void emplace_in_bucket(const bucket_index_type idx, Args &&... args)
void clear_bit(const size_t i)
Set the i-th bit to false.
bool is_set(const size_t i) const
std::array< ranked_key_type, num_buckets > mins_
void swap_top_bucket(bucket_data_type &exchange_bucket)
void clear()
Clears all internal queues and resets insertion limit.
void clear_bit(const size_t i)
bucket_map_type bucket_map_
This class implements a monotonic integer min priority queue, more specific a multi-level radix heap...
bucket_index_type emplace(const key_type key, Args &&... args)
radix_heap_detail::BitArray< num_buckets > filled_
BitArrayRecursive() noexcept
RadixHeap(KeyExtract key_extract=KeyExtract { })
std::vector< value_type > bucket_data_type
Compute the rank of an integer x (i.e.
std::array< bucket_data_type, num_buckets > buckets_data_
std::array< child_type, root_size > child_array_type
auto make_radix_heap(KeyExtract &&key_extract) -> RadixHeap< DataType, KeyExtract, decltype(key_extract(std::declval< DataType >())), Radix >
Helper to easily derive type of RadixHeap for a pre-C++17 compiler.
A BitArray of fixed size supporting reading, setting, and clearing of individual bits.
void clear_all()
Sets all bits to false.
bool empty() const
True if all bits are false.
static constexpr bool debug
void set_bit(const size_t i)
static constexpr size_t num_buckets_(size_t bits)
static constexpr rank_type rank_of_int(int_type i)
void set_bit(const size_t i)
Set the i-th bit to true.
static uint_pair min()
return an uint_pair instance containing the smallest value possible
void push_to_bucket(const bucket_index_type idx, const value_type &value)
bucket_index_type get_bucket(const value_type &value) const
bucket_index_type push(const value_type &value)
Insert element with priority key.
std::pair< size_t, size_t > get_index_(size_t i) const
void clear_bit(const size_t i)
static constexpr auto div_ceil(const IntegralN &n, const IntegralK &k) -> decltype(n+k)
calculate n div k with rounding up, for n and k positive!
child_array_type children_
bucket_index_type get_bucket_key(const key_type key) const
static constexpr bool use_identity_
Int upper_bound(const size_t idx) const
Return largest key possible in bucket idx assuming insertion_limit==0.
typename std::conditional< Size<=32, uint32_t, uint64_t >::type uint_type
static const size_t digits
number of binary digits (bits) in uint_pair
bool is_set(const size_t i) const
bool is_set(const size_t i) const
Returns value of the i-th.
static constexpr rank_type sign_bit_