Skip to content

Commit

Permalink
added bitset functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
drexlerd committed Feb 11, 2024
1 parent bbe36f0 commit 8e1a2f1
Show file tree
Hide file tree
Showing 4 changed files with 365 additions and 28 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ else()
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -Wall -g3 -ggdb")
endif()

set(CMAKE_BUILD_TYPE "Release")
# set(CMAKE_BUILD_TYPE "Release")

message(STATUS "Build configuration: ${CMAKE_BUILD_TYPE}")

Expand Down
214 changes: 210 additions & 4 deletions include/flatmemory/details/types/bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

#include <algorithm>
#include <cassert>
#include <cmath>
#include <tuple>
#include <iostream>
#include <string>
Expand Down Expand Up @@ -267,6 +268,7 @@ namespace flatmemory
static constexpr std::size_t block_size = sizeof(Block) * 8;
static constexpr Block block_zeroes = 0;
static constexpr Block block_ones = Block(-1);
static constexpr std::size_t no_position = std::size_t(-1);

/* Implement IBuilder interface. */
template <typename>
Expand All @@ -280,6 +282,7 @@ namespace flatmemory

/* Write dynamic info */
buffer_size_type buffer_size = Layout<Bitset<Block>>::blocks_position;

// Write blocks
m_blocks.finish();
buffer_size += m_buffer.write(Layout<Bitset<Block>>::blocks_position, m_blocks.buffer().data(), m_blocks.buffer().size());
Expand All @@ -304,13 +307,157 @@ namespace flatmemory
}
}

std::size_t get_lsb_position(Block n) const
{
assert(n != 0);
const Block v = n & (-n);
return static_cast<std::size_t>(log2(v));
}

public:
[[nodiscard]] bool& get_default_bit_value() { return m_default_bit_value; }
Builder() : m_default_bit_value(false) {}
// Initialize the bitset with a certain size
Builder(std::size_t size)
: m_default_bit_value(false)
, m_blocks((size / (sizeof(Block) * 8)) + 1, block_zeroes) {}

[[nodiscard]] auto& get_blocks() { return m_blocks; }
Builder(std::size_t size, bool default_bit_value)
: m_default_bit_value(default_bit_value)
, m_blocks((size / (sizeof(Block) * 8)) + 1, default_bit_value ? block_ones : block_zeroes) { }


/**
* Operators
*/

template <IsBitset Other>
bool operator<(const Other& other) const
{
// Fetch data
const auto &other_blocks = other.get_blocks();
bool other_default_bit_value = other.get_default_bit_value();

std::size_t common_size = std::min(m_blocks.size(), other_blocks.size());

for (std::size_t index = 0; index < common_size; ++index)
{
if (m_blocks[index] < other_blocks[index])
{
return true;
}
}

std::size_t max_size = std::max(m_blocks.size(), other_blocks.size());

for (std::size_t index = common_size; index < max_size; ++index)
{
Block this_value = index < m_blocks.size() ? m_blocks[index] : (m_default_bit_value ? block_ones : block_zeroes);
Block other_value = index < other_blocks.size() ? other_blocks[index] : (other_default_bit_value ? block_ones : block_zeroes);

if (this_value < other_value)
{
return true;
}
}

return false;
}

template <IsBitset Other>
[[nodiscard]] Builder &operator|=(const Other &other)
bool operator==(const Other& other) const
{
// Fetch data
const auto &other_blocks = other.get_blocks();
bool other_default_bit_value = other.get_default_bit_value();

std::size_t common_size = std::min(m_blocks.size(), other_blocks.size());

for (std::size_t index = 0; index < common_size; ++index)
{
if (m_blocks[index] != other_blocks[index])
{
return false;
}
}

std::size_t max_size = std::max(m_blocks.size(), other_blocks.size());

for (std::size_t index = common_size; index < max_size; ++index)
{
Block this_value = index < m_blocks.size() ? m_blocks[index] : (m_default_bit_value ? block_ones : block_zeroes);
Block other_value = index < other_blocks.size() ? other_blocks[index] : (other_default_bit_value ? block_ones : block_zeroes);

if (this_value != other_value)
{
return false;
}
}

return true;
}


/**
* Modifiers
*/

// Set a bit at a specific position
void set(std::size_t position)
{
const std::size_t index = position / block_size; // Find the index in the vector
const std::size_t offset = position % block_size; // Find the offset within the std::size_t

if (index >= m_blocks.size())
{
m_blocks.resize(index + 1, m_default_bit_value ? block_ones : block_zeroes);
}

m_blocks[index] |= (static_cast<Block>(1) << offset); // Set the bit at the offset
}

// Unset a bit at a specific position
void unset(std::size_t position)
{
const std::size_t index = position / block_size; // Find the index in the vector
const std::size_t offset = position % block_size; // Find the offset within the std::size_t

if (index >= m_blocks.size())
{
m_blocks.resize(index + 1, m_default_bit_value ? block_ones : block_zeroes);
}

m_blocks[index] &= ~(static_cast<Block>(1) << offset); // Set the bit at the offset
}

// Unset all bits
void unset_all()
{
for (auto& value : m_blocks) {
value = (m_default_bit_value) ? block_ones : block_zeroes;
}
}

// Unset all bits for a given default_bit_value
void unset_all(bool default_bit_value)
{
m_default_bit_value = default_bit_value;
unset_all();
}

Builder& operator~()
{
m_default_bit_value = !m_default_bit_value;

for (Block& value : m_blocks)
{
value = ~value;
}

return *this;
}

template <IsBitset Other>
Builder& operator|=(const Other &other)
{
// Fetch data
const auto &other_blocks = other.get_blocks();
Expand All @@ -334,7 +481,7 @@ namespace flatmemory
}

template <IsBitset Other>
[[nodiscard]] Builder &operator&=(const Other &other)
Builder& operator&=(const Other &other)
{
// Fetch data
const auto &other_blocks = other.get_blocks();
Expand All @@ -357,6 +504,54 @@ namespace flatmemory
return *this;
}


/**
* Lookup
*/

// Get the value of a bit at a specific position
bool get(std::size_t position) const {
{
const std::size_t index = position / block_size;

if (index < m_blocks.size())
{
const std::size_t offset = position % block_size;
return (m_blocks[index] & (static_cast<Block>(1) << offset)) != 0;
}
else
{
return m_default_bit_value;
}
}
}

// Find the next set bit, inclusive the given position
std::size_t next_set_bit(std::size_t position) const
{
std::size_t index = position / block_size;
std::size_t offset = position % block_size;

while (index < m_blocks.size())
{
// Shift so that we start checking from the offset
const Block value = m_blocks[index] >> offset;

if (value)
{
// If there are set bits in the current value
const auto lsb_position = get_lsb_position(value);
return index * block_size + offset + lsb_position;
}

// Reset offset for the next value
offset = 0;
index++;
}

return no_position;
}

[[nodiscard]] size_t hash() const
{
const auto default_block = m_default_bit_value ? block_ones : block_zeroes;
Expand All @@ -375,6 +570,17 @@ namespace flatmemory
MurmurHash3_x64_128(&m_blocks[0], length, seed, hash);
return static_cast<std::size_t>(hash[0] + 0x9e3779b9 + (hash[1] << 6) + (hash[1] >> 2));
}


/**
* Getters
*/

[[nodiscard]] bool& get_default_bit_value() { return m_default_bit_value; }
[[nodiscard]] const bool& get_default_bit_value() const { return m_default_bit_value; }

[[nodiscard]] auto& get_blocks() { return m_blocks; }
[[nodiscard]] const auto& get_blocks() const { return m_blocks; }
};
}

Expand Down
61 changes: 38 additions & 23 deletions include/flatmemory/details/types/vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,44 +142,59 @@ namespace flatmemory
[[nodiscard]] const auto& get_buffer_impl() const { return m_buffer; }

public:
Builder() = default;
explicit Builder(size_t count) : m_data(count) { }
explicit Builder(size_t count, const T_& value) : m_data(count, value) { }

/**
* empty
* Element access
*/
[[nodiscard]] constexpr bool empty() const {
return m_data.empty();
[[nodiscard]] T_& operator[](size_t pos) {
assert(pos < m_data.size());
return m_data[pos];
}

[[nodiscard]] const T_& operator[](size_t pos) const {
assert(pos < m_data.size());
return m_data[pos];
}


/**
* size
* Iterators
*/
[[nodiscard]] constexpr size_t size() const {
return m_data.size();

decltype(auto) begin() { return m_data.begin(); }
decltype(auto) begin() const { return m_data.begin(); }
decltype(auto) end() { return m_data.end(); }
decltype(auto) end() const { return m_data.end(); }

/**
* Capacity
*/

[[nodiscard]] constexpr bool empty() const {
return m_data.empty();
}

/* operator[] stl */
[[nodiscard]] T_& operator[](size_t pos) {
assert(pos < m_data.size());
return m_data[pos];
[[nodiscard]] constexpr size_t size() const {
return m_data.size();
}

/* push back stl */

/**
* Modifiers
*/
void push_back(T_&& element) { m_data.push_back(std::move(element)) ;}
void push_back(const T_& element) { m_data.push_back(element) ;}

/**
* Resize
*
* Resizing a vector of views needs additional caution
* since the default constructed views are not meaningful.
*/
/// @brief
///
/// Resizing a vector of views needs additional caution
/// since the default constructed views are not meaningful.
/// @param count
void resize(size_t count) { m_data.resize(count, T_()); }
void resize(size_t count, const T_& value) { m_data.resize(count, value); }

/**
* iterators
*/
decltype(auto) begin() { return m_data.begin(); }
decltype(auto) end() { return m_data.end(); }
};


Expand Down
Loading

0 comments on commit 8e1a2f1

Please sign in to comment.