mirror of
https://github.com/NGSolve/netgen.git
synced 2024-12-24 21:10:33 +05:00
Add BitArray from NGSolve
Deprecate method BitArray::Set(), instead use either SetBit() or SetBitAtomic()
This commit is contained in:
parent
1584da69ae
commit
b27f7f3bb6
@ -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
143
libsrc/core/bitarray.cpp
Normal 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
200
libsrc/core/bitarray.hpp
Normal 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
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "archive.hpp"
|
||||
#include "array.hpp"
|
||||
#include "bitarray.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "flags.hpp"
|
||||
#include "localheap.hpp"
|
||||
|
@ -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"
|
||||
|
@ -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>)
|
||||
|
35
tests/pytest/test_bitarray.py
Normal file
35
tests/pytest/test_bitarray.py
Normal 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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user