31 #include "../support/common.hpp"
50 template <util::AllocType AT = util::AllocType::MALLOC>
class Rank9Sel :
public Rank9<AT>,
public Select {
52 static const int log2_ones_per_inventory = 9;
53 static const int ones_per_inventory = 1 << log2_ones_per_inventory;
54 static const uint64_t inventory_mask = ones_per_inventory - 1;
57 uint64_t inventory_size;
75 const uint64_t num_words = (
num_bits + 63) / 64;
76 inventory_size = (this->
num_ones + ones_per_inventory - 1) / ones_per_inventory;
79 printf(
"Number of ones per inventory item: %d\n", ones_per_inventory);
81 assert(ones_per_inventory <= 8 * 64);
83 inventory.
size(inventory_size + 1);
84 subinventory.
size((num_words + 3) / 4);
87 for (uint64_t i = 0; i < num_words; i++)
88 for (
int j = 0; j < 64; j++)
89 if (
bits[i] & 1ULL << j) {
90 if ((d & inventory_mask) == 0) {
91 inventory[d >> log2_ones_per_inventory] = i * 64 + j;
92 assert(this->
counts[(i / 8) * 2] <= d);
93 assert(this->
counts[(i / 8) * 2 + 2] > d);
100 inventory[inventory_size] = ((num_words + 3) & ~3ULL) * 64;
103 printf(
"Inventory size: %" PRId64
"\n", inventory_size);
104 printf(
"Inventory entries filled: %" PRId64
"\n", d / ones_per_inventory + 1);
112 uint64_t *s, first_bit, index, span, block_span, block_left, counts_at_start;
114 for (uint64_t i = 0; i < num_words; i++)
115 for (
int j = 0; j < 64; j++)
116 if (
bits[i] & 1ULL << j) {
117 if ((d & inventory_mask) == 0) {
118 first_bit = i * 64 + j;
119 index = d >> log2_ones_per_inventory;
120 assert(inventory[index] == first_bit);
121 s = &subinventory[(inventory[index] / 64) / 4];
122 span = (inventory[index + 1] / 64) / 4 - (inventory[index] / 64) / 4;
124 counts_at_start = this->
counts[((inventory[index] / 64) / 8) * 2];
125 block_span = (inventory[index + 1] / 64) / 8 - (inventory[index] / 64) / 8;
126 block_left = (inventory[index] / 64) / 8;
130 else if (span >= 256)
132 else if (span >= 128)
134 else if (span >= 16) {
135 assert(((block_span + 8) & -8LL) + 8 <= span * 4);
138 for (k = 0; k < block_span; k++) {
139 assert(((uint16_t *)s)[k + 8] == 0);
140 ((uint16_t *)s)[k + 8] = this->
counts[(block_left + k + 1) * 2] - counts_at_start;
143 for (; k < ((block_span + 8) & -8LL); k++) {
144 assert(((uint16_t *)s)[k + 8] == 0);
145 ((uint16_t *)s)[k + 8] = 0xFFFFU;
148 assert(block_span / 8 <= 8);
150 for (k = 0; k < block_span / 8; k++) {
151 assert(((uint16_t *)s)[k] == 0);
152 ((uint16_t *)s)[k] = this->
counts[(block_left + (k + 1) * 8) * 2] - counts_at_start;
156 assert(((uint16_t *)s)[k] == 0);
157 ((uint16_t *)s)[k] = 0xFFFFU;
159 }
else if (span >= 2) {
160 assert(((block_span + 8) & -8LL) <= span * 4);
163 for (k = 0; k < block_span; k++) {
164 assert(((uint16_t *)s)[k] == 0);
165 ((uint16_t *)s)[k] = this->
counts[(block_left + k + 1) * 2] - counts_at_start;
168 for (; k < ((block_span + 8) & -8LL); k++) {
169 assert(((uint16_t *)s)[k] == 0);
170 ((uint16_t *)s)[k] = 0xFFFFU;
177 assert(s[d & inventory_mask] == 0);
178 s[d & inventory_mask] = i * 64 + j;
181 assert(((uint32_t *)s)[d & inventory_mask] == 0);
182 assert(i * 64 + j - first_bit < (1ULL << 32));
183 ((uint32_t *)s)[d & inventory_mask] = i * 64 + j - first_bit;
186 assert(((uint16_t *)s)[d & inventory_mask] == 0);
187 assert(i * 64 + j - first_bit < (1 << 16));
188 ((uint16_t *)s)[d & inventory_mask] = i * 64 + j - first_bit;
197 const uint64_t inventory_index_left =
rank >> log2_ones_per_inventory;
198 assert(inventory_index_left <= inventory_size);
200 const uint64_t inventory_left = inventory[inventory_index_left];
201 const uint64_t block_right = inventory[inventory_index_left + 1] / 64;
202 uint64_t block_left = inventory_left / 64;
203 const uint64_t span = block_right / 4 - block_left / 4;
204 const uint64_t *
const s = &subinventory[block_left / 4];
205 uint64_t count_left, rank_in_block;
208 printf(
"Initially, rank: %" PRId64
" block_left: %" PRId64
" block_right: %" PRId64
" span: %" PRId64
"\n",
rank, block_left, block_right, span);
213 count_left = block_left / 4 & ~1;
214 assert(rank < this->
counts[count_left + 2]);
215 rank_in_block =
rank - this->
counts[count_left];
217 printf(
"Single span; rank_in_block: %" PRId64
" block_left: %" PRId64
"\n", rank_in_block, block_left);
219 }
else if (span < 16) {
221 count_left = block_left / 4 & ~1;
222 const uint64_t rank_in_superblock =
rank - this->
counts[count_left];
223 const uint64_t rank_in_superblock_step_16 = rank_in_superblock *
ONES_STEP_16;
225 const uint64_t first = s[0], second = s[1];
230 printf(
"rank_in_superblock: %" PRId64
" (%" PRIx64
") %" PRIx64
" %" PRIx64
"\n", rank_in_superblock, rank_in_superblock, s[0], s[1]);
233 block_left += where * 4;
235 rank_in_block =
rank - this->counts[count_left];
236 assert(rank_in_block < 512);
238 printf(
"Found where (1): %d rank_in_block: %" PRId64
" block_left: %" PRId64
"\n", where, rank_in_block, block_left);
239 printf(
"superthis->counts: %016" PRIx64
" %016" PRIx64
"\n", s[0], s[1]);
241 }
else if (span < 128) {
243 count_left = block_left / 4 & ~1;
244 const uint64_t rank_in_superblock =
rank - this->
counts[count_left];
245 const uint64_t rank_in_superblock_step_16 = rank_in_superblock *
ONES_STEP_16;
247 const uint64_t first = s[0], second = s[1];
249 assert(where0 <= 16);
250 const uint64_t first_bis = s[where0 + 2], second_bis = s[where0 + 2 + 1];
253 block_left += where1 * 4;
254 count_left += where1;
255 rank_in_block =
rank - this->counts[count_left];
256 assert(rank_in_block < 512);
259 printf(
"Found where (2): %d rank_in_block: %" PRId64
" block_left: %" PRId64
"\n", where1, rank_in_block, block_left);
261 }
else if (span < 256) {
262 return ((uint16_t *)s)[
rank % ones_per_inventory] + inventory_left;
263 }
else if (span < 512) {
264 return ((uint32_t *)s)[
rank % ones_per_inventory] + inventory_left;
266 return s[
rank % ones_per_inventory];
269 const uint64_t rank_in_block_step_9 = rank_in_block *
ONES_STEP_9;
270 const uint64_t subcounts = this->
counts[count_left + 1];
271 const uint64_t offset_in_block = (
ULEQ_STEP_9(subcounts, rank_in_block_step_9) *
ONES_STEP_9 >> 54 & 0x7);
273 const uint64_t word = block_left + offset_in_block;
274 const uint64_t rank_in_word = rank_in_block - (subcounts >> ((offset_in_block - 1) & 7) * 9 & 0x1FF);
275 assert(offset_in_block <= 7);
278 printf(
"rank_in_block: %" PRId64
" offset_in_block: %" PRId64
" rank_in_word: %" PRId64
"\n", rank_in_block, offset_in_block, rank_in_word);
279 printf(
"subcounts: ");
280 for (
int i = 0; i < 7; i++) printf(
"%" PRId64
" ", subcounts >> i * 9 & 0x1FF);
285 assert(rank_in_word < 64);
288 printf(
"Returning %" PRId64
"\n", word * UINT64_C(64) +
select64(this->
bits[word], rank_in_word));
290 return word * UINT64_C(64) +
select64(this->
bits[word], rank_in_word);
294 return this->
counts.
bitCount() -
sizeof(this->
counts) * 8 + inventory.
bitCount() -
sizeof(inventory) * 8 + subinventory.
bitCount() -
sizeof(subinventory) * 8 +
sizeof(*
this) * 8;