move in bitset and test
This commit is contained in:
parent
4bda751f76
commit
e78e4ea8d5
@ -2,8 +2,19 @@ cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
|
|||||||
|
|
||||||
project(solanaceae)
|
project(solanaceae)
|
||||||
|
|
||||||
|
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||||
|
set(SOLANACEAE_UTIL_STANDALONE ON)
|
||||||
|
else()
|
||||||
|
set(SOLANACEAE_UTIL_STANDALONE OFF)
|
||||||
|
endif()
|
||||||
|
message("II SOLANACEAE_UTIL_STANDALONE " ${SOLANACEAE_UTIL_STANDALONE})
|
||||||
|
|
||||||
|
option(SOLANACEAE_UTIL_BUILD_TESTING "Build the solanaceae_util tests" ${SOLANACEAE_UTIL_STANDALONE})
|
||||||
|
message("II SOLANACEAE_UTIL_BUILD_TESTING " ${SOLANACEAE_UTIL_BUILD_TESTING})
|
||||||
|
|
||||||
add_library(solanaceae_util
|
add_library(solanaceae_util
|
||||||
./solanaceae/util/span.hpp
|
./solanaceae/util/span.hpp
|
||||||
|
./solanaceae/util/bitset.hpp
|
||||||
|
|
||||||
./solanaceae/util/utils.hpp
|
./solanaceae/util/utils.hpp
|
||||||
./solanaceae/util/utils.cpp
|
./solanaceae/util/utils.cpp
|
||||||
@ -40,3 +51,11 @@ target_compile_features(solanaceae_file2 PUBLIC cxx_std_17)
|
|||||||
target_link_libraries(solanaceae_file2 PUBLIC
|
target_link_libraries(solanaceae_file2 PUBLIC
|
||||||
solanaceae_util
|
solanaceae_util
|
||||||
)
|
)
|
||||||
|
|
||||||
|
########################################
|
||||||
|
|
||||||
|
if (SOLANACEAE_UTIL_BUILD_TESTING)
|
||||||
|
include(CTest)
|
||||||
|
add_subdirectory(./test)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
107
solanaceae/util/bitset.hpp
Normal file
107
solanaceae/util/bitset.hpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
14
test/CMakeLists.txt
Normal file
14
test/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.9...3.24 FATAL_ERROR)
|
||||||
|
|
||||||
|
project(solanaceae)
|
||||||
|
|
||||||
|
add_executable(solanaceae_util_bitset_test
|
||||||
|
./bitset_tests.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(solanaceae_util_bitset_test PUBLIC
|
||||||
|
solanaceae_util
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(NAME solanaceae_util_bitset_test COMMAND solanaceae_util_bitset_test)
|
||||||
|
|
245
test/bitset_tests.cpp
Normal file
245
test/bitset_tests.cpp
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
#include <solanaceae/util/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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user