2
* Copyright (c) 2010 Daisuke Okanohara
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above Copyright
9
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above Copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the authors nor the names of its contributors
16
* may be used to endorse or promote products derived from this
17
* software without specific prior written permission.
21
#include "bit_array.h"
26
BitArray::BitArray() : length_(0), one_num_(0){
29
BitArray::BitArray(uint64_t length){
33
BitArray::~BitArray(){
36
uint64_t BitArray::length() const {
40
uint64_t BitArray::one_num() const{
44
void BitArray::Init(uint64_t length){
47
uint64_t block_num = (length + BLOCK_BITNUM - 1) / BLOCK_BITNUM;
48
bit_blocks_.resize(block_num);
51
void BitArray::Clear(){
52
std::vector<uint64_t>().swap(bit_blocks_);
53
std::vector<uint64_t>().swap(rank_tables_);
58
void BitArray::Build() {
60
uint64_t table_num = ((bit_blocks_.size() + TABLE_INTERVAL - 1) / TABLE_INTERVAL) + 1;
61
rank_tables_.resize(table_num);
62
for (size_t i = 0; i < bit_blocks_.size(); ++i){
63
if ((i % TABLE_INTERVAL) == 0){
64
rank_tables_[i/TABLE_INTERVAL] = one_num_;
66
one_num_ += PopCount(bit_blocks_[i]);
68
rank_tables_.back() = one_num_;
71
void BitArray::SetBit(uint64_t bit, uint64_t pos) {
73
bit_blocks_[pos / BLOCK_BITNUM] |= (1LLU << (pos % BLOCK_BITNUM));
76
uint64_t BitArray::Rank(uint64_t bit, uint64_t pos) const {
77
if (pos > length_) return NOTFOUND;
78
if (bit) return RankOne(pos);
79
else return pos - RankOne(pos);
82
uint64_t BitArray::Select(uint64_t bit, uint64_t rank) const {
84
if (rank > one_num_) return NOTFOUND;
86
if (rank > length_ - one_num_) return NOTFOUND;
89
uint64_t block_pos = SelectOutBlock(bit, rank);
90
uint64_t block = (bit) ? bit_blocks_[block_pos] : ~bit_blocks_[block_pos];
91
return block_pos * BLOCK_BITNUM + SelectInBlock(block, rank);
94
uint64_t BitArray::SelectOutBlock(uint64_t bit, uint64_t& rank) const {
95
// binary search over tables
97
uint64_t right = rank_tables_.size();
99
uint64_t mid = (left + right) / 2;
100
uint64_t length = BLOCK_BITNUM * TABLE_INTERVAL * mid;
101
if (GetBitNum(rank_tables_[mid], length, bit) < rank) {
108
uint64_t table_ind = (left != 0) ? left - 1: 0;
109
uint64_t block_pos = table_ind * TABLE_INTERVAL;
110
rank -= GetBitNum(rank_tables_[table_ind],
111
block_pos * BLOCK_BITNUM,
114
// sequential search over blocks
115
for ( ; block_pos < bit_blocks_.size(); ++block_pos){
116
uint64_t rank_next= GetBitNum(PopCount(bit_blocks_[block_pos]), BLOCK_BITNUM, bit);
117
if (rank <= rank_next){
125
uint64_t BitArray::SelectInBlock(uint64_t x, uint64_t rank) {
126
uint64_t x1 = x - ((x & 0xAAAAAAAAAAAAAAAALLU) >> 1);
127
uint64_t x2 = (x1 & 0x3333333333333333LLU) + ((x1 >> 2) & 0x3333333333333333LLU);
128
uint64_t x3 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FLLU;
132
uint64_t rank_next = (x3 >> pos) & 0xFFLLU;
133
if (rank <= rank_next) break;
137
uint64_t v2 = (x2 >> pos) & 0xFLLU;
143
uint64_t v1 = (x1 >> pos) & 0x3LLU;
149
uint64_t v0 = (x >> pos) & 0x1LLU;
158
uint64_t BitArray::Lookup(uint64_t pos) const {
159
return (bit_blocks_[pos / BLOCK_BITNUM] >> (pos % BLOCK_BITNUM)) & 1LLU;
163
uint64_t BitArray::RankOne(uint64_t pos) const {
164
uint64_t block_ind = pos / BLOCK_BITNUM;
165
uint64_t table_ind = block_ind / TABLE_INTERVAL;
166
assert(table_ind < rank_tables_.size());
168
uint64_t rank = rank_tables_[table_ind];
169
for (uint64_t i = table_ind * TABLE_INTERVAL; i < block_ind; ++i){
170
rank += PopCount(bit_blocks_[i]);
172
rank += PopCountMask(bit_blocks_[block_ind], pos % BLOCK_BITNUM);
176
/** Return the Hamming weight of x. */
177
uint64_t BitArray::PopCount(uint64_t x)
179
#if ENABLE_POPCNT && __GNUC__ && __x86_64__
180
__asm__("popcnt %1,%0" : "=r" (x) : "r" (x));
183
x = (x & 0x5555555555555555ULL) +
184
((x >> 1) & 0x5555555555555555ULL);
185
x = (x & 0x3333333333333333ULL) +
186
((x >> 2) & 0x3333333333333333ULL);
187
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
195
uint64_t BitArray::PopCountMask(uint64_t x, uint64_t offset) {
196
if (offset == 0) return 0;
197
return PopCount(x & ((1LLU << offset) - 1));
200
uint64_t BitArray::GetBitNum(uint64_t one_num, uint64_t num, uint64_t bit) {
201
if (bit) return one_num;
202
else return num - one_num;
205
void BitArray::PrintForDebug(std::ostream& os) const {
206
for (uint64_t i = 0; i < length_; ++i){
207
if (Lookup(i)) os << "1";
209
if (((i+1) % 8) == 0) {
215
void BitArray::Save(std::ostream& os) const{
216
os.write((const char*)(&length_), sizeof(length_));
217
os.write((const char*)(&bit_blocks_[0]), sizeof(bit_blocks_[0]) * bit_blocks_.size());
220
void BitArray::Load(std::istream& is){
222
is.read((char*)(&length_), sizeof(length_));
224
is.read((char*)(&bit_blocks_[0]), sizeof(bit_blocks_[0]) * bit_blocks_.size());