Pixie
Loading...
Searching...
No Matches
succinct_monotone_stack.h
1#pragma once
2
31
32#include <bit>
33#include <cassert>
34#include <cstddef>
35#include <cstdint>
36#include <vector>
37
39
54class SuccinctIncreasingStack {
55 public:
56 explicit SuccinctIncreasingStack(std::size_t capacity)
57 : words_(word_count(capacity)),
58 nonempty_words_(word_count(words_.size())),
59 nonempty_super_words_(word_count(nonempty_words_.size())),
60 capacity_(capacity) {}
61
65 bool empty() const { return size_ == 0; }
66
72 std::size_t top() const {
73 assert(!empty());
74 return top_key_;
75 }
76
84 void push(std::size_t key) {
85 assert(key < capacity_);
86 assert(empty() || top() < key);
87
88 const std::size_t block = block_index(key);
89 words_[block] |= std::uint64_t{1} << block_position(key);
90 set_nonempty(block);
91 top_key_ = key;
92 ++size_;
93 }
94
100 void pop() {
101 assert(!empty());
102
103 const std::size_t block = block_index(top_key_);
104 std::uint64_t word = words_[block];
105 word &= ~(std::uint64_t{1} << block_position(top_key_));
106 words_[block] = word;
107
108 --size_;
109 if (size_ == 0) {
110 if (word == 0) {
111 clear_nonempty(block);
112 }
113 top_key_ = 0;
114 return;
115 }
116
117 if (word != 0) {
118 top_key_ = block * kBlockBits + highest_bit(word);
119 return;
120 }
121
122 clear_nonempty(block);
123 const std::size_t previous_block = previous_nonempty_block(block);
124 const std::uint64_t previous_word = words_[previous_block];
125 assert(previous_word != 0);
126 top_key_ = previous_block * kBlockBits + highest_bit(previous_word);
127 }
128
129 private:
130 static constexpr std::size_t kBlockBits = 64;
131 static constexpr std::size_t kBlockShift = 6;
132 static constexpr std::size_t kBlockMask = kBlockBits - 1;
133
134 static std::size_t word_count(std::size_t bit_count) {
135 return (bit_count + kBlockBits - 1) / kBlockBits;
136 }
137
138 static std::size_t block_index(std::size_t key) { return key >> kBlockShift; }
139
140 static std::size_t block_position(std::size_t key) {
141 return key & kBlockMask;
142 }
143
144 static std::size_t highest_bit(std::uint64_t word) {
145 assert(word != 0);
146 return static_cast<std::size_t>(std::bit_width(word) - 1);
147 }
148
149 static std::uint64_t low_bits(std::size_t count) {
150 return count == 0 ? 0 : ((std::uint64_t{1} << count) - 1);
151 }
152
153 void set_nonempty(std::size_t block) {
154 const std::size_t summary = block_index(block);
155 const std::uint64_t bit = std::uint64_t{1} << block_position(block);
156 if ((nonempty_words_[summary] & bit) == 0) {
157 nonempty_words_[summary] |= bit;
158 nonempty_super_words_[block_index(summary)] |= std::uint64_t{1}
159 << block_position(summary);
160 }
161 }
162
163 void clear_nonempty(std::size_t block) {
164 const std::size_t summary = block_index(block);
165 nonempty_words_[summary] &= ~(std::uint64_t{1} << block_position(block));
166 if (nonempty_words_[summary] == 0) {
167 nonempty_super_words_[block_index(summary)] &=
168 ~(std::uint64_t{1} << block_position(summary));
169 }
170 }
171
172 std::size_t previous_nonempty_block(std::size_t block) const {
173 assert(block > 0);
174 std::size_t summary = block_index(block);
175 const std::size_t summary_position = block_position(block);
176 if (summary_position != 0) {
177 const std::uint64_t same_summary =
178 nonempty_words_[summary] & low_bits(summary_position);
179 if (same_summary != 0) {
180 return summary * kBlockBits + highest_bit(same_summary);
181 }
182 }
183
184 std::size_t super = block_index(summary);
185 const std::size_t super_position = block_position(summary);
186 std::uint64_t super_mask =
187 super_position == 0
188 ? 0
189 : nonempty_super_words_[super] & low_bits(super_position);
190 while (super_mask == 0) {
191 assert(super > 0);
192 --super;
193 super_mask = nonempty_super_words_[super];
194 }
195
196 const std::size_t previous_summary =
197 super * kBlockBits + highest_bit(super_mask);
198 assert(previous_summary < nonempty_words_.size());
199 const std::uint64_t previous_summary_word =
200 nonempty_words_[previous_summary];
201 assert(previous_summary_word != 0);
202 return previous_summary * kBlockBits + highest_bit(previous_summary_word);
203 }
204
205 std::vector<std::uint64_t> words_;
206 std::vector<std::uint64_t> nonempty_words_;
207 std::vector<std::uint64_t> nonempty_super_words_;
208 std::size_t capacity_ = 0;
209 std::size_t size_ = 0;
210 std::size_t top_key_ = 0;
211};
212
213} // namespace pixie::rmq::utils
void pop()
Remove the current top key.
Definition succinct_monotone_stack.h:100
bool empty() const
Whether the logical stack is empty.
Definition succinct_monotone_stack.h:65
std::size_t top() const
Return the current top key.
Definition succinct_monotone_stack.h:72
void push(std::size_t key)
Push a key larger than the current top key.
Definition succinct_monotone_stack.h:84
Definition succinct_monotone_stack.h:38