#pragma once #include "../common/compat.hpp" #include "../string/StringBuilder.hpp" #include "../string/String.hpp" #include <limits> #include <stdlib.h> namespace sprawl { namespace collections { template<uint64_t maxBits> class BitSet; class BitVector; } } template<uint64_t maxBits> class sprawl::collections::BitSet { public: BitSet() : m_bitArray() { Reset(); } void Set(uint64_t bit) { size_t offset = getOffset_(bit); m_bitArray[offset] |= (uint64_t(1) << bit); } void Unset(uint64_t bit) { size_t offset = getOffset_(bit); m_bitArray[offset] &= ~(uint64_t(1) << bit); } void Flip(uint64_t bit) { size_t offset = getOffset_(bit); m_bitArray[offset] ^= (uint64_t(1) << bit); } bool HasBit(uint64_t bit) const { size_t offset = getOffset_(bit); return ((m_bitArray[offset] & (uint64_t(1) << bit)) != 0); } constexpr uint64_t Size() const { return maxBits; } bool Any() const { uint64_t testArray[sizeof(m_bitArray) / sizeof(uint64_t)]; memset(testArray, 0, sizeof(testArray)); return (memcmp(testArray, m_bitArray, sizeof(m_bitArray)) != 0); } bool None() const { return !Any(); } bool All() const { //Memcmp would be nice here, but since we might have extra unused bits, //getting the right value to compare against is a bit tough. for(size_t i = 0; i < Size(); ++i) { if(!HasBit(i)) { return false; } } return true; } void Reset() { memset(m_bitArray, 0, sizeof(m_bitArray)); } uint64_t Count() const { uint64_t result = 0; size_t const numIndexes = sizeof(m_bitArray)/sizeof(int64_t); for(size_t i = 0; i < numIndexes; ++i) { result += countBitsSet_(m_bitArray[i]); } return result; } sprawl::String ToString() { sprawl::StringBuilder builder(maxBits, false); for(size_t i = maxBits; i > 0; --i) { if(HasBit(i-1)) { builder << "1"; } else { builder << "0"; } } return builder.Str(); } private: uint64_t countBitsSet_(uint64_t value) const { uint64_t result = 0; for(uint64_t i = 0; i < 64; ++i) { if((value & (uint64_t(1) << i)) != 0) { ++result; } } return result; } size_t getOffset_(uint64_t& bit) const { size_t offset = bit / 64; bit = bit % 64; return offset; } uint64_t m_bitArray[(maxBits / 64) + 1]; }; class sprawl::collections::BitVector { public: BitVector() : m_bitArray(new uint64_t[1]) , m_size(0) { Reset(); } ~BitVector() { delete[] m_bitArray; } BitVector(BitVector const& other) : m_bitArray(new uint64_t[other.m_size / 64 + 1]) , m_size(other.m_size) { memcpy(m_bitArray, other.m_bitArray, (other.m_size / 64 + 1) * sizeof(uint64_t)); } BitVector(BitVector&& other) : m_bitArray(other.m_bitArray) , m_size(other.m_size) { other.m_bitArray = new uint64_t[1]; other.m_size = 0; } BitVector& operator=(BitVector const& other) { m_bitArray = new uint64_t[other.m_size / 64 + 1]; m_size = other.m_size; memcpy(m_bitArray, other.m_bitArray, (other.m_size / 64 + 1) * sizeof(uint64_t)); return *this; } BitVector& operator=(BitVector&& other) { m_bitArray = other.m_bitArray; m_size = other.m_size; other.m_bitArray = new uint64_t[1]; other.m_size = 0; return *this; } void Set(uint64_t bit) { size_t offset = getOffset_(bit); checkGrow_(offset, bit); m_bitArray[offset] |= (uint64_t(1) << bit); } void Unset(uint64_t bit) { size_t offset = getOffset_(bit); checkGrow_(offset, bit); m_bitArray[offset] &= ~(uint64_t(1) << bit); } void Flip(uint64_t bit) { size_t offset = getOffset_(bit); checkGrow_(offset, bit); m_bitArray[offset] ^= (uint64_t(1) << bit); } bool HasBit(uint64_t bit) const { size_t offset = getOffset_(bit); if(offset > m_size / 64) { return false; } return ((m_bitArray[offset] & (uint64_t(1) << bit)) != 0); } uint64_t Size() const { return m_size; } bool Any() const { uint64_t* testArray = (uint64_t*)alloca((m_size / 64 + 1) * sizeof(uint64_t)); memset(testArray, 0, (m_size / 64 + 1) * sizeof(uint64_t)); return (memcmp(testArray, m_bitArray, ((m_size / 64) + 1) * sizeof(uint64_t)) != 0); } bool None() const { return !Any(); } bool All() const { //Memcmp would be nice here, but since we might have extra unused bits, //getting the right value to compare against is a bit tough. for(size_t i = 0; i < Size(); ++i) { if(!HasBit(i)) { return false; } } return true; } void Reset() { memset(m_bitArray, 0, ((m_size / 64) + 1) * sizeof(uint64_t)); } uint64_t Count() const { uint64_t result = 0; size_t const numIndexes = m_size / 64 + 1; for(size_t i = 0; i < numIndexes; ++i) { result += countBitsSet_(m_bitArray[i]); } return result; } sprawl::String ToString() { sprawl::StringBuilder builder(m_size, false); for(size_t i = m_size; i > 0; --i) { if(HasBit(i-1)) { builder << "1"; } else { builder << "0"; } } return builder.Str(); } private: void checkGrow_(uint64_t newOffset, uint64_t bit) { if(newOffset > (m_size / 64)) { uint64_t* newArray = new uint64_t[newOffset + 1]; memset(newArray, 0, (newOffset + 1) * sizeof(uint64_t)); memcpy(newArray, m_bitArray, ((m_size / 64) + 1) * sizeof(uint64_t)); delete[] m_bitArray; m_bitArray = newArray; } uint64_t const fullBit = newOffset * 64 + bit; if(m_size <= fullBit) { m_size = fullBit + 1; } } uint64_t countBitsSet_(uint64_t value) const { uint64_t result = 0; for(uint64_t i = 0; i < 64; ++i) { if((value & (uint64_t(1) << i)) != 0) { ++result; } } return result; } size_t getOffset_(uint64_t& bit) const { size_t offset = bit / 64; bit = bit % 64; return offset; } uint64_t* m_bitArray; size_t m_size; };
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 23398 | ququlala | "Forking branch Mainline of shadauxcat-libsprawl to ququlala-libsprawl." | ||
//guest/ShadauxCat/Sprawl/Mainline/collections/BitVector.hpp | |||||
#7 | 19906 | ShadauxCat |
- Added tag, compile time string type - Since tag requires visual studio 2015, removed compatibility code for earlier versions of visual studio - Improved compiler detection - Added endianness detection - Added template if/else helper - Fixed bug with murmur3 64 bit - Added seed argument for murmur3 #review-19907 |
||
#6 | 14216 | ShadauxCat |
-Moved some global sprawl::Strings into local scope in json serialization test because of initialization order issues in the memory allocator on mac. This is a temporary fix, and a real fix will come by making the pool allocator work in explicitly-sized pieces and putting all the code for those pieces into a cpp file. -Fixed a large number of warnings on mac/linux that were exposed by fixes to csbuild -Fixed compile errors on mac due to malloc and alloca not being defined, fixed by #include <stdlib.h> in appropriate places -Fixed mac os x trying to link against pthread erroneously -Provided os x implementation of time library -Fixed compile errors on os x due to std::unordered_map whining about the difference between an allocator that allocates std::pair<key, value> and one that allocates std::pair<key const, value>, which, of course, is that the allocator will be no different at all. -Fixed an actual issue where one unordered_map was allocating only key_type instead of std::pair<key_type, value_type> -Fixed a memory leak where coroutine objects would never be cleaned up because either Yield() or reactivate_() will never return (and thus never clean up their stack memory and thus never release any dynamic memory held in stack objects) depending on the situation - if the function runs to completion, reactivate_() never returns after calling swapcontext(); meanwhile, if the function does not run to completion, Yield() never returns after calling Pause(). This behavior will need to be well-documented because it will affect client-side code as well. Stack memory within a coroutine should not rely on RAII behavior. -Fixed compile failure when creating a StlWrapper with a const value_type #review-14217 |
||
#5 | 14121 | ShadauxCat |
-Fixed msvc compile errors (msvc sucks at decltype, btw...) -Fixed BitVector and BitSet being broken on msvc due to 1L being 32-bit rather than 64-bit -Fixed Deque being broken on 32-bit systems due to an errant int64_t -Changed types of deque indexes from size_t to ssize_t; since they have to be signed for a moment to handle circling the buffer, the sign bit is lost for capacity anyway, and using signed indexes means... -Deque and Vector now support negative indexing a la python list #review-14122 |
||
#4 | 14115 | ShadauxCat |
Add missing copy/move/assignment/destructor for BitVector, variadic constructor for Coroutine #review-14116 |
||
#3 | 14098 | ShadauxCat |
Added BitVector (BitSet that dynamically increases in size as needed to accommodate the highest bit that gets set). Later I'll add proper operators for both (i.e., BitSet(010101) & BitSet(011011) = BitSet(010001)) #review-14099 |
||
#2 | 14096 | ShadauxCat |
Getting offset a more sensible way in bitset. #review-14097 |
||
#1 | 14092 | ShadauxCat |
Added BitSet (statically sized at compile time) and corresponding unit test. BitVector (dynamically sized to the largest input it receives) to come next. #review-14093 |