blob: d9f52607c99f85def753f9688f94f4addd899a8e [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// Utility functions for dealing with a byte array as if it were a bitmap.
#ifndef KUDU_UTIL_BITMAP_H
#define KUDU_UTIL_BITMAP_H
#include <cstddef>
#include <cstdint>
#include <ostream>
#include <string>
#include <glog/logging.h>
#include "kudu/gutil/bits.h"
#include "kudu/gutil/port.h"
namespace kudu {
// Return the number of bytes necessary to store the given number of bits.
inline size_t BitmapSize(size_t num_bits) {
return (num_bits + 7) / 8;
}
// Set the given bit.
inline void BitmapSet(uint8_t *bitmap, size_t idx) {
bitmap[idx >> 3] |= 1 << (idx & 7);
}
// Switch the given bit to the specified value.
inline void BitmapChange(uint8_t *bitmap, size_t idx, bool value) {
bitmap[idx >> 3] = (bitmap[idx >> 3] & ~(1 << (idx & 7))) | ((!!value) << (idx & 7));
}
// Clear the given bit.
inline void BitmapClear(uint8_t *bitmap, size_t idx) {
bitmap[idx >> 3] &= ~(1 << (idx & 7));
}
// Test/get the given bit.
inline bool BitmapTest(const uint8_t *bitmap, size_t idx) {
return bitmap[idx >> 3] & (1 << (idx & 7));
}
// Merge the two bitmaps using bitwise or. Both bitmaps should have at least
// n_bits valid bits.
inline void BitmapMergeOr(uint8_t *dst, const uint8_t *src, size_t n_bits) {
size_t n_bytes = BitmapSize(n_bits);
for (size_t i = 0; i < n_bytes; i++) {
*dst++ |= *src++;
}
}
// Set bits from offset to (offset + num_bits) to the specified value
void BitmapChangeBits(uint8_t *bitmap, size_t offset, size_t num_bits, bool value);
// Find the first bit of the specified value, starting from the specified offset.
bool BitmapFindFirst(const uint8_t *bitmap, size_t offset, size_t bitmap_size,
bool value, size_t *idx);
// Find the first set bit in the bitmap, at the specified offset.
inline bool BitmapFindFirstSet(const uint8_t *bitmap, size_t offset,
size_t bitmap_size, size_t *idx) {
return BitmapFindFirst(bitmap, offset, bitmap_size, true, idx);
}
// Find the first zero bit in the bitmap, at the specified offset.
inline bool BitmapFindFirstZero(const uint8_t *bitmap, size_t offset,
size_t bitmap_size, size_t *idx) {
return BitmapFindFirst(bitmap, offset, bitmap_size, false, idx);
}
// Returns true if the bitmap contains only ones.
inline bool BitMapIsAllSet(const uint8_t *bitmap, size_t offset, size_t bitmap_size) {
DCHECK_LT(offset, bitmap_size);
size_t idx;
return !BitmapFindFirstZero(bitmap, offset, bitmap_size, &idx);
}
// Returns true if the bitmap contains only zeros.
inline bool BitmapIsAllZero(const uint8_t *bitmap, size_t offset, size_t bitmap_size) {
DCHECK_LT(offset, bitmap_size);
size_t idx;
return !BitmapFindFirstSet(bitmap, offset, bitmap_size, &idx);
}
std::string BitmapToString(const uint8_t *bitmap, size_t num_bits);
// Iterator which yields ranges of set and unset bits.
// Example usage:
// bool value;
// size_t size;
// BitmapIterator iter(bitmap, n_bits);
// while ((size = iter.Next(&value))) {
// printf("bitmap block len=%lu value=%d\n", size, value);
// }
class BitmapIterator {
public:
BitmapIterator(const uint8_t *map, size_t num_bits)
: offset_(0), num_bits_(num_bits), map_(map)
{}
bool done() const {
return (num_bits_ - offset_) == 0;
}
void SeekTo(size_t bit) {
DCHECK_LE(bit, num_bits_);
offset_ = bit;
}
size_t Next(bool *value) {
size_t len = num_bits_ - offset_;
if (PREDICT_FALSE(len == 0))
return(0);
*value = BitmapTest(map_, offset_);
size_t index;
if (BitmapFindFirst(map_, offset_, num_bits_, !(*value), &index)) {
len = index - offset_;
} else {
index = num_bits_;
}
offset_ = index;
return len;
}
private:
size_t offset_;
size_t num_bits_;
const uint8_t *map_;
};
// Iterator which yields the set bits in a bitmap.
// Example usage:
// for (TrueBitIterator iter(bitmap, n_bits);
// !iter.done();
// ++iter) {
// int next_onebit_position = *iter;
// }
class TrueBitIterator {
public:
TrueBitIterator(const uint8_t *bitmap, size_t n_bits)
: bitmap_(bitmap),
cur_byte_(0),
cur_byte_idx_(0),
n_bits_(n_bits),
n_bytes_(BitmapSize(n_bits_)),
bit_idx_(0) {
if (n_bits_ == 0) {
cur_byte_idx_ = 1; // sets done
} else {
cur_byte_ = bitmap[0];
AdvanceToNextOneBit();
}
}
TrueBitIterator &operator ++() {
DCHECK(!done());
DCHECK(cur_byte_ & 1);
cur_byte_ &= (~1);
AdvanceToNextOneBit();
return *this;
}
bool done() const {
return cur_byte_idx_ >= n_bytes_;
}
size_t operator *() const {
DCHECK(!done());
return bit_idx_;
}
private:
void AdvanceToNextOneBit() {
while (cur_byte_ == 0) {
cur_byte_idx_++;
if (cur_byte_idx_ >= n_bytes_) return;
cur_byte_ = bitmap_[cur_byte_idx_];
bit_idx_ = cur_byte_idx_ * 8;
}
DVLOG(2) << "Found next nonzero byte at " << cur_byte_idx_
<< " val=" << cur_byte_;
DCHECK_NE(cur_byte_, 0);
int set_bit = Bits::FindLSBSetNonZero(cur_byte_);
bit_idx_ += set_bit;
cur_byte_ >>= set_bit;
}
const uint8_t *bitmap_;
uint8_t cur_byte_;
uint8_t cur_byte_idx_;
const size_t n_bits_;
const size_t n_bytes_;
size_t bit_idx_;
};
} // namespace kudu
#endif