#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 | |
|---|---|---|---|---|---|
| #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 |