11 #ifndef TLX_CONTAINER_RADIX_HEAP_HEADER 12 #define TLX_CONTAINER_RADIX_HEAP_HEADER 18 #include <type_traits> 29 namespace radix_heap_detail {
41 template <
typename Int>
44 static_assert(std::is_integral<Int>::value,
45 "SignedInt has to be an integral type");
49 using rank_type =
typename std::make_unsigned<int_type>::type;
75 "Rank of minimum is not zero");
77 "Rank of minimum+1 is not one");
78 static_assert(
rank_of_int(std::numeric_limits<int_type>::max())
79 == std::numeric_limits<rank_type>::max(),
80 "Rank of maximum is not maximum rank");
81 static_assert(
rank_of_int(std::numeric_limits<int_type>::max()) >
83 "Rank of maximum is not larger than rank of zero");
90 template <
size_t Size,
bool SizeIsAtmost64>
93 template <
size_t Size>
96 static constexpr
size_t leaf_width = 6;
98 static_assert(width > leaf_width,
99 "Size has to be larger than 2**leaf_width");
100 static constexpr
size_t root_width = (width % leaf_width)
101 ? (width % leaf_width)
103 static constexpr
size_t child_width = width - root_width;
106 static constexpr
size_t root_size =
div_ceil(Size, child_type::size);
112 static constexpr
size_t size = Size;
120 void set_bit(const
size_t i) {
121 const auto idx = get_index_(i);
122 root_.set_bit(idx.first);
123 children_[idx.first].set_bit(idx.second);
127 const auto idx = get_index_(i);
128 children_[idx.first].clear_bit(idx.second);
129 if (children_[idx.first].empty())
130 root_.clear_bit(idx.first);
134 const auto idx = get_index_(i);
135 return children_[idx.first].is_set(idx.second);
140 for (
auto& child : children_)
145 return root_.empty();
151 const size_t child_idx = root_.find_lsb();
152 const size_t child_val = children_[child_idx].find_lsb();
154 return child_idx * child_type::size + child_val;
163 return { i / child_type::size, i % child_type::size };
167 template <
size_t Size>
170 static_assert(Size <= 64,
"Support at most 64 bits");
171 using uint_type =
typename std::conditional<
172 Size <= 32, uint32_t, uint64_t>::type;
175 static constexpr
size_t size = Size;
195 return (flags_ & (
uint_type(1) << i)) != 0;
225 template <
size_t Size>
231 static constexpr
size_t size = Size;
233 explicit BitArray() noexcept = default;
240 void set_bit(const
size_t i) {
251 return impl_.is_set(i);
261 return impl_.empty();
267 return impl_.find_lsb();
274 template <
unsigned Radix,
typename Int>
277 static_assert(std::is_unsigned<Int>::value,
"Require unsigned integer");
282 size_t operator () (
const Int x,
const Int insertion_limit)
const {
283 constexpr Int mask = (1u << radix_bits) - 1;
285 assert(x >= insertion_limit);
287 const auto diff = x ^ insertion_limit;
290 const auto diff_in_bit = (8 *
sizeof(Int) - 1) -
clz(diff);
292 const auto row = diff_in_bit / radix_bits;
293 const auto bucket_in_row = ((x >> (radix_bits * row)) & mask) - row;
295 const auto result = row * Radix + bucket_in_row;
302 assert(idx < num_buckets);
305 return static_cast<Int
>(idx);
307 const size_t row = (idx - 1) / (Radix - 1);
308 const auto digit =
static_cast<Int
>(idx - row * (Radix - 1));
310 return digit << radix_bits * row;
315 assert(idx < num_buckets);
317 if (idx == num_buckets - 1)
318 return std::numeric_limits<Int>::max();
320 return lower_bound(idx + 1) - 1;
325 return (bits >= radix_bits)
326 ? (Radix - 1) + num_buckets_(bits - radix_bits)
332 static constexpr
size_t num_buckets =
333 num_buckets_(std::numeric_limits<Int>::digits) + 1;
337 template <
typename KeyType,
typename DataType>
341 KeyType operator () (
const std::pair<KeyType, DataType>& p)
const {
375 template <
typename ValueType,
typename KeyExtract,
376 typename KeyType,
unsigned Radix = 8>
380 "Radix has to be power of two");
382 static constexpr
bool debug =
false;
389 static constexpr
unsigned radix = Radix;
398 static constexpr
unsigned num_layers =
400 static constexpr
unsigned num_buckets = bucket_map_type::num_buckets;
405 explicit RadixHeap(KeyExtract key_extract = KeyExtract { })
406 : key_extract_(key_extract) {
419 return get_bucket_key(key_extract_(value));
423 const auto enc = Encoder::rank_of_int(key);
424 assert(enc >= insertion_limit_);
426 return bucket_map_(enc, insertion_limit_);
433 template <
typename... Args>
435 const auto enc = Encoder::rank_of_int(key);
436 assert(enc >= insertion_limit_);
437 const auto idx = bucket_map_(enc, insertion_limit_);
439 emplace_in_bucket(idx, std::forward<Args>(args) ...);
445 template <
typename... Args>
447 return emplace(key, key, std::forward<Args>(args) ...);
454 template <
typename... Args>
456 if (buckets_data_[idx].empty()) filled_.set_bit(idx);
457 buckets_data_[idx].emplace_back(std::forward<Args>(args) ...);
459 const auto enc = Encoder::rank_of_int(
460 key_extract_(buckets_data_[idx].back()));
461 if (mins_[idx] > enc) mins_[idx] = enc;
462 assert(idx == bucket_map_(enc, insertion_limit_));
469 const auto enc = Encoder::rank_of_int(key_extract_(value));
470 assert(enc >= insertion_limit_);
472 const auto idx = bucket_map_(enc, insertion_limit_);
474 push_to_bucket(idx, value);
484 const auto enc = Encoder::rank_of_int(key_extract_(value));
486 assert(enc >= insertion_limit_);
487 assert(idx == get_bucket(value));
489 if (buckets_data_[idx].empty()) filled_.set_bit(idx);
490 buckets_data_[idx].push_back(value);
492 if (mins_[idx] > enc) mins_[idx] = enc;
510 const auto first = filled_.find_lsb();
511 return Encoder::int_at_rank(mins_[first]);
518 return buckets_data_[current_bucket_].back();
525 buckets_data_[current_bucket_].pop_back();
526 if (buckets_data_[current_bucket_].empty())
527 filled_.clear_bit(current_bucket_);
538 assert(exchange_bucket.empty());
539 size_ -= buckets_data_[current_bucket_].size();
540 buckets_data_[current_bucket_].swap(exchange_bucket);
542 filled_.clear_bit(current_bucket_);
547 for (
auto& x : buckets_data_) x.clear();
555 size_t current_bucket_{ 0 };
561 std::array<ranked_key_type, num_buckets>
mins_;
569 std::fill(mins_.begin(), mins_.end(),
570 std::numeric_limits<ranked_key_type>::max());
579 if (
TLX_LIKELY(!buckets_data_[current_bucket_].empty())) {
580 assert(current_bucket_ < Radix);
585 mins_[current_bucket_] = std::numeric_limits<ranked_key_type>::max();
589 const auto first_non_empty = filled_.
find_lsb();
592 assert(first_non_empty < num_buckets);
594 for (
size_t i = 0; i < first_non_empty; i++) {
595 assert(buckets_data_[i].empty());
596 assert(mins_[i] == std::numeric_limits<ranked_key_type>::max());
599 assert(!buckets_data_[first_non_empty].empty());
606 current_bucket_ = first_non_empty;
612 const auto new_ins_limit = mins_[first_non_empty];
613 assert(new_ins_limit > insertion_limit_);
614 insertion_limit_ = new_ins_limit;
617 auto& data_source = buckets_data_[first_non_empty];
619 for (
auto& x : data_source) {
621 assert(key >= mins_[first_non_empty]);
622 assert(first_non_empty == mins_.size() - 1
623 || key < mins_[first_non_empty + 1]);
624 const auto idx = bucket_map_(key, insertion_limit_);
625 assert(idx < first_non_empty);
628 if (buckets_data_[idx].empty()) filled_.
set_bit(idx);
629 buckets_data_[idx].push_back(std::move(x));
630 if (mins_[idx] > key) mins_[idx] = key;
636 mins_[first_non_empty] = std::numeric_limits<ranked_key_type>::max();
640 current_bucket_ = filled_.
find_lsb();
641 assert(current_bucket_ < Radix);
642 assert(!buckets_data_[current_bucket_].empty());
643 assert(mins_[current_bucket_] >= insertion_limit_);
651 template <
typename DataType,
unsigned Radix = 8,
typename KeyExtract =
void>
653 RadixHeap<DataType, KeyExtract,
654 decltype(key_extract(std::declval<DataType>())), Radix> {
657 decltype(key_extract(DataType{ })), Radix > {
667 template <
typename KeyType,
typename DataType,
unsigned Radix = 8>
669 std::pair<KeyType, DataType>,
678 #endif // !TLX_CONTAINER_RADIX_HEAP_HEADER bool is_set(const size_t i) const
typename Encoder::rank_type ranked_key_type
bucket_index_type get_bucket(const value_type &value) const
Int upper_bound(const size_t idx) const
Return largest key possible in bucket idx assuming insertion_limit==0.
std::pair< size_t, size_t > get_index_(size_t i) const
static unsigned ffs(int i)
find first set bit in integer, or zero if none are set.
static constexpr int_type int_at_rank(rank_type r)
Returns the r-th smallest number of int_r.
bool is_set(const size_t i) const
Returns value of the i-th.
typename std::make_unsigned< int_type >::type rank_type
bucket_index_type emplace(const key_type key, Args &&...args)
Construct and insert element with priority key.
bool empty() const
True if all bits are false.
void emplace_in_bucket(const bucket_index_type idx, Args &&...args)
Construct and insert element into bucket idx (useful if an item was inserted into the same bucket dir...
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)
Exchanges the top buckets with an empty user provided bucket.
const value_type & top()
Returns currently smallest key and data.
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...
radix_heap_detail::BitArray< num_buckets > filled_
size_t size() const
Returns number of elements currently stored.
static uint32_t min(uint32_t x, uint32_t y)
BitArrayRecursive() noexcept
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
Indicates whether size() == 0.
bucket_index_type emplace_keyfirst(const key_type key, Args &&...args)
In case the first parameter can be directly casted into key_type, using this method avoid repeating i...
void set_bit(const size_t i)
static constexpr size_t num_buckets_(size_t bits)
RadixHeap(KeyExtract key_extract=KeyExtract{})
size_t find_lsb() const
Finds the bit with smallest index that is set.
static constexpr rank_type rank_of_int(int_type i)
Maps value i to its rank in int_type.
key_type peak_top_key() const
Returns currently smallest key without updating the insertion limit.
void set_bit(const size_t i)
Set the i-th bit to true.
Internal implementation of BitArray; do not invoke directly.
void push_to_bucket(const bucket_index_type idx, const value_type &value)
Insert element into specific bucket (useful if an item was inserted into the same bucket directly bef...
bucket_index_type push(const value_type &value)
Insert element with priority key.
void clear_bit(const size_t i)
bucket_index_type get_bucket_key(const key_type key) const
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_
static constexpr bool use_identity_
typename std::conditional< Size<=32, uint32_t, uint64_t >::type uint_type
void pop()
Removes smallest element.
Int lower_bound(const size_t idx) const
Return smallest key possible in bucket idx assuming insertion_limit==0.
static constexpr rank_type sign_bit_