mirror of
https://github.com/NGSolve/netgen.git
synced 2024-11-11 16:49:16 +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
|
add_library(ngcore SHARED
|
||||||
archive.cpp
|
archive.cpp
|
||||||
|
bitarray.cpp
|
||||||
localheap.cpp
|
localheap.cpp
|
||||||
logging.cpp
|
logging.cpp
|
||||||
flags.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
|
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
|
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
|
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)
|
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel)
|
||||||
|
|
||||||
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
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 "archive.hpp"
|
||||||
#include "array.hpp"
|
#include "array.hpp"
|
||||||
|
#include "bitarray.hpp"
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
#include "flags.hpp"
|
#include "flags.hpp"
|
||||||
#include "localheap.hpp"
|
#include "localheap.hpp"
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "ngcore_api.hpp" // for operator new
|
#include "ngcore_api.hpp" // for operator new
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
|
#include <pybind11/operators.h>
|
||||||
|
|
||||||
#include "array.hpp"
|
#include "array.hpp"
|
||||||
#include "archive.hpp"
|
#include "archive.hpp"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
#include "python_ngcore.hpp"
|
#include "python_ngcore.hpp"
|
||||||
|
#include "bitarray.hpp"
|
||||||
|
|
||||||
|
|
||||||
using namespace ngcore;
|
using namespace ngcore;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -11,6 +12,83 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT
|
|||||||
ExportArray<size_t>(m);
|
ExportArray<size_t>(m);
|
||||||
ExportArray<double>(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")
|
py::class_<Flags>(m, "Flags")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def("__str__", &ToString<Flags>)
|
.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