blob: dc2f1e86d2e9ead8db9a57639c6124425e9a557e [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.
*/
#ifndef DBCOMMON_SRC_DBCOMMON_UTILS_BOOL_BUFFER_H_
#define DBCOMMON_SRC_DBCOMMON_UTILS_BOOL_BUFFER_H_
#include <algorithm>
#include <climits>
#include <iostream>
#include <memory>
#include <set>
#include <utility>
#include "dbcommon/utils/byte-buffer.h"
namespace dbcommon {
extern uint64_t bit_to_bytes[256];
class BoolBuffer {
public:
// The constructor.
// @param ownData Indicating it owns the data or not.
// @return void
explicit BoolBuffer(bool ownData) : buffer_(ownData), bitBuffer_(false) {}
~BoolBuffer() {}
// Get the size of buffer in number of bools
// @return The size of the buffer in number of bools
size_t size() const { return buffer_.size(); }
// Get the address of the buffer
// @return The buffer address
const bool *data() const {
return reinterpret_cast<const bool *>(buffer_.data());
}
bool *data() { return reinterpret_cast<bool *>(buffer_.data()); }
// Get the bitmap size in Bytes
// @return the size in Bytes
size_t bitDataSizeInBytes() const {
return bitmapBitLengthToByteLength(size());
}
// Set the external data address and size (in #bools)
// @param d The external data
// @param dataSize The size of of the external data (in #bools).
// @return void
void setBitData(const char *data, size_t numBools) {
if (!buffer_.getOwnData()) buffer_.reset(true);
int numBits = bitmapBitLengthToByteLength(numBools);
// when this numBits > 1, reserve only can alloc 8 bytes,
// so buffer overflow
buffer_.reserve(8 * numBits);
buffer_.resize(numBools);
uint64_t *nulls = reinterpret_cast<uint64_t *>(buffer_.data());
for (size_t i = 0; i < numBits; i++) {
nulls[i] = bit_to_bytes[static_cast<uint8_t>(data[i])];
}
}
// update the external data address and size (in #bools)
// @param d The external data
// @param dataSize The size of of the external data (in #bools).
// @return void
// note: it do not change the buffer size at all, you should
// assure enough memory space before call this method
void updateBitData(size_t idx, const char *data, size_t numBools) {
assert(buffer_.getOwnData());
assert(size() >= idx + numBools);
size_t bitBytes = numBools / CHAR_BIT;
// when this numBits > 1, reserve only can alloc 8 bytes,
// so buffer overflow
uint64_t *nulls = reinterpret_cast<uint64_t *>(buffer_.data() + idx);
for (size_t i = 0; i < bitBytes; ++i) {
nulls[i] = bit_to_bytes[static_cast<uint8_t>(data[i])];
}
uint32_t pos = idx + bitBytes * CHAR_BIT;
bool *pNulls = reinterpret_cast<bool *>(buffer_.data() + pos);
size_t left = numBools - bitBytes * CHAR_BIT;
uint8_t lastByte = static_cast<uint8_t>(data[bitBytes]);
assert(left < CHAR_BIT);
for (size_t i = 0; i < left; ++i) {
pNulls[i] = (lastByte >> i) & 0x1;
}
}
const char *getBitData() const {
if (!bitBuffer_.getOwnData()) bitBuffer_.reset(true);
bitBuffer_.resize(bitDataSizeInBytes());
const bool *nulls = reinterpret_cast<bool *>(buffer_.data());
uint64_t size = this->size() / CHAR_BIT * CHAR_BIT;
for (uint64_t i = 0; i < size; i += 8) {
uint8_t v = 0;
v |= nulls[i] | nulls[i + 1] << 1 | nulls[i + 2] << 2 |
nulls[i + 3] << 3 | nulls[i + 4] << 4 | nulls[i + 5] << 5 |
nulls[i + 6] << 6 | nulls[i + 7] << 7;
bitBuffer_.data()[i / CHAR_BIT] = v;
}
if (0 != this->size() % CHAR_BIT) {
char &v = bitBuffer_.data()[this->size() / CHAR_BIT];
v = 0;
for (uint64_t i = size; i < this->size(); ++i) {
v |= nulls[i] << (i % CHAR_BIT);
}
}
return bitBuffer_.data();
}
// Append a value of type T.
// @param value The value to write
// @return void
void append(bool value) {
assert(buffer_.getOwnData());
buffer_.append<char>(value);
}
void append(const bool *buffer, uint64_t size) {
if (size > 0) {
for (size_t i = 0; i < size; ++i) {
append(buffer[i]);
}
}
}
// Get the index(th) bit value.
// @param index The index
// @return The bit value
bool get(uint64_t index) const {
assert(index < size() || size() > 0);
return buffer_.data()[index];
}
char getChar(uint64_t index) const {
assert(index < size() || size() > 0);
return buffer_.data()[index];
}
void set(uint64_t index, bool value) {
assert(index < size() || size() > 0);
buffer_.data()[index] = value;
}
// Resize the buffer. If the buffer size >= numOfBools, nothing changed
// otherwise, expend the buffer.
// @param numOfBools The new size
// @return void
void resize(uint64_t numOfBools) { buffer_.resize(numOfBools); }
void reserve(uint64_t size) { buffer_.reserve(size); }
static size_t bitmapBitLengthToByteLength(uint64_t n) {
return (((n) + 7) >> 3);
}
bool *getBools() const {
bool *nulls = reinterpret_cast<bool *>(buffer_.data());
return nulls;
}
char *getChars() const {
char *nulls = reinterpret_cast<char *>(buffer_.data());
return nulls;
}
void setBools(const char *inputs, uint64_t sz) {
assert(inputs != nullptr && sz >= 0);
buffer_.setData(inputs, sz);
}
void setReserseBools(const char *inputs, uint64_t sz) {
assert(inputs != nullptr && sz >= 0);
if (!buffer_.getOwnData()) buffer_.reset(true);
buffer_.resize(sz);
for (uint64_t i = 0; i < sz; i++) {
buffer_.set<bool>(i, !inputs[i]);
}
}
// Reserve space and set all data values input(true/false)
void setReserseBools(const bool input, uint64_t sz) {
assert(sz >= 0);
if (!buffer_.getOwnData()) buffer_.reset(true);
buffer_.resize(sz);
for (uint64_t i = 0; i < sz; i++) {
buffer_.set<bool>(i, input);
}
}
std::unique_ptr<ByteBuffer> getReverseBools() {
uint64_t size = this->size();
std::unique_ptr<ByteBuffer> buf(new ByteBuffer(true));
buf->resize(size);
for (uint64_t i = 0; i < size; i++) {
buf->set<char>(i, !buffer_.get<char>(i));
}
return std::move(buf);
}
void swap(BoolBuffer &buf) {
buffer_.swap(buf.buffer_);
bitBuffer_.swap(buf.bitBuffer_);
}
void materialize(SelectList *sel) { buffer_.materialize<bool>(sel); }
void reset(bool ownData) { buffer_.reset(ownData); }
// Reset the BoolBuffer according to the input NullVector.
void reset(size_t plainSize, const SelectList *sel,
const bool *__restrict__ nulls1,
const bool *__restrict__ nulls2 = nullptr,
const bool *__restrict__ nulls3 = nullptr);
// Reset the BoolBuffer according to the input NullValue.
void reset(size_t plainSize, const SelectList *sel, bool null);
private:
ByteBuffer buffer_;
mutable ByteBuffer bitBuffer_;
};
} // namespace dbcommon
#endif // DBCOMMON_SRC_DBCOMMON_UTILS_BOOL_BUFFER_H_