Add util::dynamic_bitset
This commit is contained in:
parent
58215fedc1
commit
981629cb74
2 changed files with 203 additions and 0 deletions
109
libs/util/include/psemek/util/dynamic_bitset.hpp
Normal file
109
libs/util/include/psemek/util/dynamic_bitset.hpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#pragma once
|
||||
|
||||
#include <psemek/util/hash.hpp>
|
||||
#include <psemek/util/span.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <climits>
|
||||
#include <compare>
|
||||
|
||||
namespace psemek::util
|
||||
{
|
||||
|
||||
struct dynamic_bitset
|
||||
{
|
||||
using storage_type = std::uint64_t;
|
||||
static constexpr std::size_t storage_bits = sizeof(storage_type) * CHAR_BIT;
|
||||
static constexpr std::size_t storage_mask = storage_bits - 1;
|
||||
|
||||
[[nodiscard]] static std::size_t bits_count_to_storage_size(std::size_t bits_count)
|
||||
{
|
||||
return (bits_count + storage_bits - 1) / storage_bits;
|
||||
}
|
||||
|
||||
dynamic_bitset() = default;
|
||||
dynamic_bitset(std::size_t size)
|
||||
: storage_(bits_count_to_storage_size(size), 0)
|
||||
{}
|
||||
|
||||
void resize(std::size_t size)
|
||||
{
|
||||
storage_.resize(bits_count_to_storage_size(size));
|
||||
}
|
||||
|
||||
void assign(std::size_t size, bool value)
|
||||
{
|
||||
storage_type storage_value = value ? -1 : 0;
|
||||
storage_.assign(bits_count_to_storage_size(size), storage_value);
|
||||
if (value)
|
||||
storage_.back() &= ((static_cast<storage_type>(1) << (size % storage_bits)) - 1);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t size() const
|
||||
{
|
||||
return storage_.size() * storage_bits;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool get(std::size_t index) const
|
||||
{
|
||||
std::size_t storage_index = index / storage_bits;
|
||||
std::size_t storage_shift = index & storage_mask;
|
||||
if (storage_index > storage_.size())
|
||||
return false;
|
||||
return (storage_[storage_index] & static_cast<storage_type>(1 << storage_shift)) != 0;
|
||||
}
|
||||
|
||||
bool set(std::size_t index, bool value)
|
||||
{
|
||||
resize(index + 1);
|
||||
|
||||
std::size_t storage_index = index / storage_bits;
|
||||
std::size_t storage_shift = index & storage_mask;
|
||||
|
||||
auto & storage_value = storage_[storage_index];
|
||||
bool result = (storage_value & static_cast<storage_type>(1 << storage_shift)) != 0;
|
||||
|
||||
if (value)
|
||||
storage_value |= static_cast<storage_type>(1 << storage_shift);
|
||||
else
|
||||
storage_value &= ~static_cast<storage_type>(1 << storage_shift);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
util::span<storage_type const> storage() const
|
||||
{
|
||||
return storage_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<storage_type> storage_;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool operator == (dynamic_bitset const & b1, dynamic_bitset const & b2);
|
||||
|
||||
[[nodiscard]] std::strong_ordering operator <=> (dynamic_bitset const & b1, dynamic_bitset const & b2);
|
||||
|
||||
[[nodiscard]] bool is_subset(dynamic_bitset const & b1, dynamic_bitset const & b2);
|
||||
|
||||
[[nodiscard]] std::size_t popcount(dynamic_bitset const & b);
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
struct hash<::psemek::util::dynamic_bitset>
|
||||
{
|
||||
std::size_t operator()(::psemek::util::dynamic_bitset const & b)
|
||||
{
|
||||
std::size_t result = 0x23d2ef655094f9aeull;
|
||||
for (auto value : b.storage())
|
||||
::psemek::util::hash_combine(result, value);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
94
libs/util/source/dynamic_bitset.cpp
Normal file
94
libs/util/source/dynamic_bitset.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#include <psemek/util/dynamic_bitset.hpp>
|
||||
|
||||
#include <bit>
|
||||
|
||||
namespace psemek::util
|
||||
{
|
||||
|
||||
[[nodiscard]] bool operator == (dynamic_bitset const & b1, dynamic_bitset const & b2)
|
||||
{
|
||||
auto storage1 = b1.storage();
|
||||
auto storage2 = b2.storage();
|
||||
|
||||
auto const min_size = std::min(storage1.size(), storage2.size());
|
||||
|
||||
std::size_t i = 0;
|
||||
for (; i < min_size; ++i)
|
||||
if (storage1[i] != storage2[i])
|
||||
return false;
|
||||
|
||||
if (storage1.size() < storage2.size())
|
||||
{
|
||||
for (; i < b2.size(); ++i)
|
||||
if (0 != storage2[i])
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; i < b1.size(); ++i)
|
||||
if (storage1[i] != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::strong_ordering operator <=> (dynamic_bitset const & b1, dynamic_bitset const & b2)
|
||||
{
|
||||
auto storage1 = b1.storage();
|
||||
auto storage2 = b2.storage();
|
||||
|
||||
auto const min_size = std::min(storage1.size(), storage2.size());
|
||||
|
||||
std::size_t i = 0;
|
||||
for (; i < min_size; ++i)
|
||||
if (auto res = storage1[i] <=> storage2[i]; res != std::strong_ordering::equal)
|
||||
return res;
|
||||
|
||||
if (storage1.size() < storage2.size())
|
||||
{
|
||||
for (; i < b2.size(); ++i)
|
||||
if (auto res = 0 <=> storage2[i]; res != std::strong_ordering::equal)
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; i < b1.size(); ++i)
|
||||
if (auto res = storage1[i] <=> 0; res != std::strong_ordering::equal)
|
||||
return res;
|
||||
}
|
||||
|
||||
return std::strong_ordering::equal;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_subset(dynamic_bitset const & b1, dynamic_bitset const & b2)
|
||||
{
|
||||
auto storage1 = b1.storage();
|
||||
auto storage2 = b2.storage();
|
||||
|
||||
auto const min_size = std::min(storage1.size(), storage2.size());
|
||||
|
||||
std::size_t i = 0;
|
||||
for (; i < min_size; ++i)
|
||||
if ((storage1[i] & storage2[i]) != storage1[i])
|
||||
return false;
|
||||
|
||||
if (storage1.size() > storage2.size())
|
||||
{
|
||||
for (; i < b1.size(); ++i)
|
||||
if (storage1[i] != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t popcount(dynamic_bitset const & b)
|
||||
{
|
||||
std::size_t result = 0;
|
||||
for (auto value : b.storage())
|
||||
result += std::popcount(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue