move bitset to util

This commit is contained in:
Green Sky 2024-06-25 12:45:28 +02:00
parent e9e38db1d5
commit 0b4041db7e
No known key found for this signature in database
4 changed files with 9 additions and 360 deletions

View File

@ -81,13 +81,13 @@ message("II SOLANACEAE_NGCFT1_SHA1_BUILD_TESTING " ${SOLANACEAE_NGCFT1_SHA1_BUIL
if (SOLANACEAE_NGCFT1_SHA1_BUILD_TESTING) if (SOLANACEAE_NGCFT1_SHA1_BUILD_TESTING)
include(CTest) include(CTest)
add_executable(bitset_tests #add_executable(bitset_tests
./solanaceae/ngc_ft1_sha1/bitset_tests.cpp # ./solanaceae/ngc_ft1_sha1/bitset_tests.cpp
) #)
target_link_libraries(bitset_tests PUBLIC #target_link_libraries(bitset_tests PUBLIC
solanaceae_sha1_ngcft1 # solanaceae_sha1_ngcft1
) #)
endif() endif()

View File

@ -1,107 +0,0 @@
#pragma once
#include <cstdint>
#include <vector>
#include <cassert>
// runtime sized bitset (stl so sad)
// size is round up to bytes
struct BitSet {
std::vector<uint8_t> _bytes;
BitSet(void) = default;
BitSet(const BitSet&) = default;
BitSet(BitSet&&) = default;
BitSet(size_t size) {
_bytes.resize((size+7)/8);
}
BitSet& operator=(const BitSet&) = default;
BitSet& operator=(BitSet&&) = default;
bool operator[](size_t pos) const {
assert(pos < size_bits());
if (pos >= size_bits()) {
return false;
}
const size_t pos_in_bytes = pos/8;
assert(pos_in_bytes < size_bytes());
if (pos_in_bytes >= size_bytes()) {
return false;
}
const size_t pos_rest_bits = pos%8;
// bits are ordered high to low
return _bytes[pos_in_bytes] & ((0x1 << 7) >> pos_rest_bits);
}
void set(size_t pos) {
assert(pos < _bytes.size()*8);
const size_t pos_in_bytes = pos/8;
assert(pos_in_bytes < _bytes.size());
const size_t pos_rest_bits = pos%8;
// bits are ordered high to low
_bytes[pos_in_bytes] |= ((0x1 << 7) >> pos_rest_bits);
}
void unset(size_t pos) {
assert(pos < _bytes.size()*8);
const size_t pos_in_bytes = pos/8;
assert(pos_in_bytes < _bytes.size());
const size_t pos_rest_bits = pos%8;
// bits are ordered high to low
_bytes[pos_in_bytes] &= ~((0x1 << 7) >> pos_rest_bits);
}
uint8_t* data(void) {
return _bytes.data();
}
size_t size_bits(void) const {
return _bytes.size()*8;
}
size_t size_bytes(void) const {
return _bytes.size();
}
BitSet& merge(const BitSet& other) {
if (other.size_bytes() > size_bytes()) {
_bytes.resize(other.size_bytes());
}
for (size_t i = 0; i < size_bytes() && i < other.size_bytes(); i++) {
_bytes[i] |= other._bytes[i];
}
return *this;
}
// start is the first bit in other relative to self
BitSet& merge(const BitSet& other, size_t start) {
// TODO: efficent implementation
size_t need_size_bits = other.size_bits() + start;
if (need_size_bits > size_bits()) {
_bytes.resize((need_size_bits+7)/8);
}
for (size_t i = 0; i < other.size_bits(); i++) {
if (other[i]) {
set(start+i);
}
}
return *this;
}
};

View File

@ -1,245 +0,0 @@
#include "./bitset.hpp"
#include <cassert>
#include <iostream>
#include <random>
int main(void) {
// ####################
for (size_t i = 1; i <= 8; i++) {
BitSet bs(i);
assert(bs._bytes.size() == 1);
}
{
BitSet bs(9);
assert(bs._bytes.size() == 2);
}
{
BitSet bs(24);
assert(bs._bytes.size() == 3);
}
// ####################
{ // simple bit sets in 1 byte
BitSet bs(8);
assert(bs._bytes.size() == 1);
assert(bs._bytes.at(0) == 0x00);
bs.set(0);
assert(bs._bytes.at(0) == 0b10000000);
assert(bs[0]);
assert(!bs[1]);
bs.set(7);
assert(bs._bytes.at(0) == 0b10000001);
assert(bs[7]);
bs.unset(0);
assert(bs._bytes.at(0) == 0b00000001);
assert(!bs[0]);
bs.set(6);
assert(bs._bytes.at(0) == 0b00000011);
assert(bs[6]);
// useless unset
bs.unset(0);
assert(bs._bytes.at(0) == 0b00000011);
assert(!bs[0]);
// useless set
bs.set(7);
assert(bs._bytes.at(0) == 0b00000011);
assert(bs[7]);
}
{ // simple bit sets in 2 bytes
BitSet bs(16);
assert(bs._bytes.size() == 2);
assert(bs._bytes.at(0) == 0x00);
assert(bs._bytes.at(1) == 0x00);
// first same as before, making sure no side effects happen
bs.set(0);
assert(bs._bytes.at(0) == 0b10000000);
assert(bs._bytes.at(1) == 0b00000000);
assert(bs[0]);
bs.set(7);
assert(bs._bytes.at(0) == 0b10000001);
assert(bs._bytes.at(1) == 0b00000000);
assert(bs[7]);
bs.unset(0);
assert(bs._bytes.at(0) == 0b00000001);
assert(bs._bytes.at(1) == 0b00000000);
bs.set(6);
assert(bs._bytes.at(0) == 0b00000011);
assert(bs._bytes.at(1) == 0b00000000);
// useless unset
bs.unset(0);
assert(bs._bytes.at(0) == 0b00000011);
assert(bs._bytes.at(1) == 0b00000000);
// useless set
bs.set(7);
assert(bs._bytes.at(0) == 0b00000011);
assert(bs._bytes.at(1) == 0b00000000);
// now in second byte
bs.set(8);
assert(bs._bytes.at(0) == 0b00000011);
assert(bs._bytes.at(1) == 0b10000000);
assert(bs[8]);
bs.set(9);
assert(bs._bytes.at(0) == 0b00000011);
assert(bs._bytes.at(1) == 0b11000000);
assert(bs[9]);
bs.set(15);
assert(bs._bytes.at(0) == 0b00000011);
assert(bs._bytes.at(1) == 0b11000001);
assert(bs[15]);
bs.unset(9);
assert(bs._bytes.at(0) == 0b00000011);
assert(bs._bytes.at(1) == 0b10000001);
}
// random long range set tests
for (size_t iml = 0; iml < 1000; iml++) {
std::default_random_engine rng(1337*17);
size_t bit_pos = rng()%16384;
size_t total_bit_count = bit_pos + rng()%16384; // so max 32768
BitSet bs(total_bit_count);
assert(bs.size_bytes() == (total_bit_count+7)/8);
for (size_t i = 0; i < total_bit_count; i++) {
assert(!bs[i]);
}
bs.set(bit_pos);
assert(bs[bit_pos]);
for (size_t i = 0; i < total_bit_count; i++) {
if (i == bit_pos) {
assert(bs[i]);
} else {
assert(!bs[i]);
}
}
}
{ // merging lets start simple
BitSet bs1(8);
BitSet bs2(8);
assert(bs1._bytes.at(0) == 0b00000000);
assert(bs2._bytes.at(0) == 0b00000000);
bs2.set(4);
assert(bs2._bytes.at(0) == 0b00001000);
bs1.merge(bs2);
assert(bs2._bytes.at(0) == 0b00001000);
assert(bs1._bytes.at(0) == 0b00001000);
}
{ // merging
BitSet bs1(8);
BitSet bs2(8);
assert(bs1._bytes.at(0) == 0b00000000);
assert(bs2._bytes.at(0) == 0b00000000);
bs1.set(1);
bs2.set(4);
assert(bs1._bytes.at(0) == 0b01000000);
assert(bs2._bytes.at(0) == 0b00001000);
bs1.merge(bs2);
assert(bs2._bytes.at(0) == 0b00001000);
assert(bs1._bytes.at(0) == 0b01001000);
}
{ // merging 2 bytes
BitSet bs1(16);
BitSet bs2(8);
assert(bs1._bytes.at(0) == 0b00000000);
assert(bs1._bytes.at(1) == 0b00000000);
assert(bs2._bytes.at(0) == 0b00000000);
bs1.set(1);
bs1.set(8);
assert(bs1._bytes.at(0) == 0b01000000);
assert(bs1._bytes.at(1) == 0b10000000);
bs2.set(4);
assert(bs2._bytes.at(0) == 0b00001000);
bs1.merge(bs2);
assert(bs2._bytes.at(0) == 0b00001000);
assert(bs1._bytes.at(0) == 0b01001000);
assert(bs1._bytes.at(1) == 0b10000000);
}
{ // merging larger in smaller
BitSet bs1(8);
BitSet bs2(16);
assert(bs1._bytes.at(0) == 0b00000000);
assert(bs2._bytes.at(0) == 0b00000000);
assert(bs2._bytes.at(1) == 0b00000000);
assert(bs1.size_bytes() != bs2.size_bytes());
bs1.set(1);
assert(bs1._bytes.at(0) == 0b01000000);
bs2.set(4);
bs2.set(8);
assert(bs2._bytes.at(0) == 0b00001000);
assert(bs2._bytes.at(1) == 0b10000000);
bs1.merge(bs2);
assert(bs2._bytes.at(0) == 0b00001000);
assert(bs2._bytes.at(1) == 0b10000000);
assert(bs1._bytes.at(0) == 0b01001000);
assert(bs1._bytes.at(1) == 0b10000000);
assert(bs1.size_bytes() == bs2.size_bytes());
}
{ // offset merge simple
BitSet bs1(16);
BitSet bs2(8);
assert(bs1._bytes.at(0) == 0b00000000);
assert(bs1._bytes.at(1) == 0b00000000);
assert(bs2._bytes.at(0) == 0b00000000);
bs1.set(1);
bs1.set(8);
assert(bs1._bytes.at(0) == 0b01000000);
assert(bs1._bytes.at(1) == 0b10000000);
bs2.set(4);
assert(bs2._bytes.at(0) == 0b00001000);
bs1.merge(bs2, 8);
assert(bs2._bytes.at(0) == 0b00001000);
assert(bs1._bytes.at(0) == 0b01000000);
assert(bs1._bytes.at(1) == 0b10001000);
}
return 0;
}

View File

@ -4,12 +4,12 @@
#include <solanaceae/message3/components.hpp> #include <solanaceae/message3/components.hpp>
#include <solanaceae/message3/registry_message_model.hpp> #include <solanaceae/message3/registry_message_model.hpp>
#include <solanaceae/util/bitset.hpp>
#include <entt/container/dense_set.hpp> #include <entt/container/dense_set.hpp>
#include "./ft1_sha1_info.hpp" #include "./ft1_sha1_info.hpp"
#include "./hash_utils.hpp" #include "./hash_utils.hpp"
#include "./bitset.hpp"
#include <vector> #include <vector>
@ -18,6 +18,7 @@
namespace Components { namespace Components {
struct Messages { struct Messages {
// dense set instead?
std::vector<Message3Handle> messages; std::vector<Message3Handle> messages;
}; };