Add BitArray from NGSolve

Deprecate method BitArray::Set(), instead use either SetBit() or
SetBitAtomic()
This commit is contained in:
Matthias Hochsteger 2019-08-28 14:10:09 +02:00
parent 1584da69ae
commit b27f7f3bb6
7 changed files with 461 additions and 2 deletions

View File

@ -1,6 +1,7 @@
add_library(ngcore SHARED
archive.cpp
bitarray.cpp
localheap.cpp
logging.cpp
flags.cpp
@ -58,7 +59,7 @@ target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE ${CMAKE_THREAD_LIBS_INIT}
install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp
exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp
array.hpp taskmanager.hpp concurrentqueue.h localheap.hpp python_ngcore.hpp flags.hpp
xbool.hpp signal.hpp
xbool.hpp signal.hpp bitarray.hpp
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel)
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)

143
libsrc/core/bitarray.cpp Normal file
View File

@ -0,0 +1,143 @@
/**************************************************************************/
/* File: bitarray.cpp */
/* Autho: Joachim Schoeberl */
/* Date: 01. Jun. 95 */
/**************************************************************************/
/*
data type BitArray
*/
#include "bitarray.hpp"
namespace ngcore
{
BitArray :: BitArray (size_t asize)
{
size = 0;
data = NULL;
SetSize (asize);
}
BitArray :: BitArray (size_t asize, LocalHeap & lh)
{
size = asize;
data = new (lh) unsigned char [Addr (size)+1];
owns_data = false;
}
BitArray :: BitArray (const BitArray & ba2)
{
size = 0;
data = NULL;
(*this) = ba2;
}
void BitArray :: SetSize (size_t asize)
{
if (size == asize) return;
if (owns_data) delete [] data;
size = asize;
data = new unsigned char [Addr (size)+1];
}
BitArray & BitArray :: Set () throw()
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] = UCHAR_MAX;
return *this;
}
BitArray & BitArray :: Clear () throw()
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] = 0;
return *this;
}
BitArray & BitArray :: Invert ()
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] ^= 255;
return *this;
}
BitArray & BitArray :: And (const BitArray & ba2)
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] &= ba2.data[i];
return *this;
}
BitArray & BitArray :: Or (const BitArray & ba2)
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] |= ba2.data[i];
return *this;
}
BitArray & BitArray :: operator= (const BitArray & ba2)
{
SetSize (ba2.Size());
if (!size)
return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] = ba2.data[i];
return *this;
}
std::ostream & operator<<(std::ostream & s, const BitArray & ba)
{
size_t n = ba.Size();
for (size_t i = 0; i < n; i++)
{
if (i % 50 == 0) s << i << ": ";
s << int(ba[i]);
if (i % 50 == 49) s << "\n";
}
s << std::flush;
return s;
}
size_t BitArray :: NumSet () const
{
size_t cnt = 0;
for (size_t i = 0; i < Size(); i++)
if (Test(i)) cnt++;
return cnt;
}
Archive & operator & (Archive & archive, BitArray & ba)
{
if (archive.Output())
{
archive << ba.Size();
for (size_t i = 0; i < ba.Size(); i++)
archive << ba[i];
}
else
{
int size;
archive & size;
ba.SetSize (size);
ba.Clear();
for (size_t i = 0; i < size; i++)
{
bool b;
archive & b;
if (b) ba.SetBit(i);
}
}
return archive;
}
}

200
libsrc/core/bitarray.hpp Normal file
View File

@ -0,0 +1,200 @@
#ifndef NETGEN_CORE_BITARRAY
#define NETGEN_CORE_BITARRAY
/**************************************************************************/
/* File: bitarray.hpp */
/* Author: Joachim Schoeberl */
/* Date: 01. Jun. 95 */
/**************************************************************************/
#include <climits>
#include <cstring>
#include <ostream>
#include "archive.hpp"
#include "array.hpp"
#include "localheap.hpp"
#include "ngcore_api.hpp"
#include "utils.hpp"
namespace ngcore
{
/**
A compressed array of bools.
Provides bit-operations and whole array operations.
*/
class BitArray
{
protected:
/// number of bits
size_t size;
/// the data
unsigned char * data;
///
bool owns_data = true;
public:
/// empty array
BitArray ()
: size(0), data(nullptr) { ; }
/// array of asize bits
NGCORE_API BitArray (size_t asize);
/// array of asize bits
NGCORE_API BitArray (size_t asize, LocalHeap & lh);
///
NGCORE_API BitArray (const BitArray & ba2);
BitArray (BitArray && ba2)
: size(ba2.size), data(ba2.data), owns_data(ba2.owns_data)
{
ba2.owns_data = false;
ba2.data = nullptr;
}
template <typename T>
NETGEN_INLINE BitArray (std::initializer_list<T> list)
: BitArray (list.size())
{
Clear();
int cnt = 0;
for (auto i = list.begin(); i < list.end(); i++, cnt++)
if (*i) SetBit(cnt);
}
/// delete data
~BitArray ()
{
if (owns_data)
delete [] data;
}
/// Set size, loose values
NGCORE_API void SetSize (size_t asize);
/// the size
size_t Size () const { return size; }
/// set all bits
NGCORE_API BitArray & Set () throw();
/// clear all bits
NGCORE_API BitArray & Clear () throw();
/// set bit i
[[deprecated("Use either SetBit() or SetBitAtomic()")]]
void Set (size_t i) { SetBitAtomic(i); }
/// set bit i ( not thread safe )
void SetBit (size_t i)
{
NETGEN_CHECK_RANGE(i, 0, size);
data[Addr(i)] |= Mask(i);
}
/// set bit i ( thread safe )
void SetBitAtomic (size_t i)
{
NETGEN_CHECK_RANGE(i, 0, size);
unsigned char * p = data+Addr(i);
unsigned char mask = Mask(i);
AsAtomic(*p) |= mask;
}
/// clear bit i
void Clear (size_t i)
{
NETGEN_CHECK_RANGE(i, 0, size);
data[Addr(i)] &= ~Mask(i);
}
/// check bit i
bool Test (size_t i) const
{
NETGEN_CHECK_RANGE(i, 0, size);
return (data[Addr(i)] & Mask(i)) ? true : false;
}
/// set all bits to b
BitArray & operator= (bool b)
{
if (b) Set();
else Clear();
return *this;
}
/// check bit i
bool operator[] (size_t i) const
{
NETGEN_CHECK_RANGE(i, 0, size);
return Test(i);
}
/// invert all bits
NGCORE_API BitArray & Invert ();
/// logical AND with ba2
NGCORE_API BitArray & And (const BitArray & ba2);
/// logical OR with ba2
NGCORE_API BitArray & Or (const BitArray & ba2);
/// copy from ba2
NGCORE_API BitArray & operator= (const BitArray & ba2);
NGCORE_API size_t NumSet () const;
private:
///
unsigned char Mask (size_t i) const
{ return char(1) << (i % CHAR_BIT); }
///
size_t Addr (size_t i) const
{ return (i / CHAR_BIT); }
};
inline BitArray & operator|= (BitArray & me, const BitArray & you)
{
me.Or(you);
return me;
}
inline BitArray & operator&= (BitArray & me, const BitArray & you)
{
me.And(you);
return me;
}
inline BitArray operator| (const BitArray & a, const BitArray & b)
{
BitArray res = a;
res |= b;
return res;
}
inline BitArray operator& (const BitArray & a, const BitArray & b)
{
BitArray res = a;
res &= b;
return res;
}
inline BitArray operator~ (const BitArray & a)
{
BitArray res = a;
res.Invert();
return res;
}
NGCORE_API std::ostream & operator<<(std::ostream & s, const BitArray & ba);
NGCORE_API Archive & operator & (Archive & archive, BitArray & ba);
} // namespace ngcore
#endif // NETGEN_CORE_BITARRAY

View File

@ -3,6 +3,7 @@
#include "archive.hpp"
#include "array.hpp"
#include "bitarray.hpp"
#include "exception.hpp"
#include "flags.hpp"
#include "localheap.hpp"

View File

@ -3,6 +3,7 @@
#include "ngcore_api.hpp" // for operator new
#include <pybind11/pybind11.h>
#include <pybind11/operators.h>
#include "array.hpp"
#include "archive.hpp"

View File

@ -1,5 +1,6 @@
#include "python_ngcore.hpp"
#include "bitarray.hpp"
using namespace ngcore;
using namespace std;
@ -11,6 +12,83 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT
ExportArray<size_t>(m);
ExportArray<double>(m);
py::class_<BitArray, shared_ptr<BitArray>> (m, "BitArray")
.def(py::init([] (size_t n) { return make_shared<BitArray>(n); }),py::arg("n"))
.def(py::init([] (const BitArray& a) { return make_shared<BitArray>(a); } ), py::arg("ba"))
.def(py::init([] (const vector<bool> & a)
{
auto ba = make_shared<BitArray>(a.size());
ba->Clear();
for (size_t i = 0; i < a.size(); i++)
if (a[i]) ba->SetBit(i);
return ba;
} ), py::arg("vec"))
.def("__str__", &ToString<BitArray>)
.def("__len__", &BitArray::Size)
.def("__getitem__", [] (BitArray & self, int i)
{
if (i < 0 || i >= self.Size())
throw py::index_error();
return self.Test(i);
}, py::arg("pos"), "Returns bit from given position")
.def("__setitem__", [] (BitArray & self, int i, bool b)
{
if (i < 0 || i >= self.Size())
throw py::index_error();
if (b) self.SetBit(i); else self.Clear(i);
}, py::arg("pos"), py::arg("value"), "Clear/Set bit at given position")
.def("__setitem__", [] (BitArray & self, py::slice inds, bool b)
{
size_t start, step, stop, n;
if (!inds.compute(self.Size(), &start, &stop, &step, &n))
throw py::error_already_set();
if (start == 0 && n == self.Size() && step == 1)
{ // base branch
if (b)
self.Set();
else
self.Clear();
}
else
{
if (b)
for (size_t i=0; i<n; i++, start+=step)
self.SetBit(start);
else
for (size_t i=0; i<n; i++, start+=step)
self.Clear(start);
}
}, py::arg("inds"), py::arg("value"), "Clear/Set bit at given positions")
.def("__setitem__", [](BitArray & self, IntRange range, bool b)
{
if (b)
for (size_t i : range)
self.SetBit(i);
else
for (size_t i : range)
self.Clear(i);
}, py::arg("range"), py::arg("value"), "Set value for range of indices" )
.def("NumSet", &BitArray::NumSet)
.def("Set", [] (BitArray & self) { self.Set(); }, "Set all bits")
.def("Set", &BitArray::SetBit, py::arg("i"), "Set bit at given position")
.def("Clear", [] (BitArray & self) { self.Clear(); }, "Clear all bits")
.def("Clear", [] (BitArray & self, int i)
{
self.Clear(i);
}, py::arg("i"), "Clear bit at given position")
.def(py::self | py::self)
.def(py::self & py::self)
.def(py::self |= py::self)
.def(py::self &= py::self)
.def(~py::self)
;
py::class_<Flags>(m, "Flags")
.def(py::init<>())
.def("__str__", &ToString<Flags>)

View File

@ -0,0 +1,35 @@
from pyngcore import BitArray
def test_bitarray():
a = BitArray(498)
assert len(a) == 498
a.Set()
for b in a:
assert b == True
a.Clear(23)
assert a[22] == True
assert a[23] == False
assert a[24] == True
a.Clear()
for b in a:
assert b == False
a.Set(23)
assert a[22] == False
assert a[23] == True
assert a[24] == False
a.Clear()
a[100:200:9] = True
for i in range(len(a)):
assert a[i] == bool(100<=i and i<200 and i%9==100%9)
ac = ~a
for b,bc in zip(a,ac):
assert b == (not bc)