netgen/libsrc/core/table.hpp

497 lines
12 KiB
C++
Raw Normal View History

2019-08-29 17:21:18 +05:00
#ifndef NETGEN_CORE_TABLE_HPP
#define NETGEN_CORE_TABLE_HPP
/**************************************************************************/
/* File: table.hpp */
/* Author: Joachim Schoeberl */
/* Date: 25. Mar. 2000 */
/**************************************************************************/
#include <atomic>
#include <iostream>
#include "array.hpp"
#include "bitarray.hpp"
#include "taskmanager.hpp"
#include "ngcore_api.hpp"
namespace ngcore
{
template <class T>
class FlatTable
{
protected:
/// number of rows
size_t size;
/// pointer to first in row
size_t * index;
/// array of data
T * data;
public:
FlatTable() = delete;
NETGEN_INLINE FlatTable(size_t as, size_t * aindex, T * adata)
: size(as), index(aindex), data(adata) { ; }
/// Size of table
NETGEN_INLINE size_t Size() const { return size; }
/// Access entry
NETGEN_INLINE const FlatArray<T> operator[] (size_t i) const
{
return FlatArray<T> (index[i+1]-index[i], data+index[i]);
}
NETGEN_INLINE T * Data() const { return data; }
NETGEN_INLINE FlatArray<T> AsArray() const
{
return FlatArray<T> (index[size]-index[0], data+index[0]);
}
NETGEN_INLINE FlatArray<size_t> IndexArray() const
{
return FlatArray<size_t> (size+1, index);
}
/// takes range starting from position start of end-start elements
NETGEN_INLINE FlatTable<T> Range (size_t start, size_t end) const
{
return FlatTable<T> (end-start, index+start, data);
}
/// takes range starting from position start of end-start elements
NETGEN_INLINE FlatTable<T> Range (T_Range<size_t> range) const
{
return FlatTable<T> (range.Size(), index+range.First(), data);
}
class Iterator
{
const FlatTable & tab;
size_t row;
public:
Iterator (const FlatTable & _tab, size_t _row) : tab(_tab), row(_row) { ; }
Iterator & operator++ () { ++row; return *this; }
FlatArray<T> operator* () const { return tab[row]; }
bool operator!= (const Iterator & it2) { return row != it2.row; }
};
Iterator begin() const { return Iterator(*this, 0); }
Iterator end() const { return Iterator(*this, size); }
};
NGCORE_API extern size_t * TablePrefixSum32 (FlatArray<unsigned int> entrysize);
NGCORE_API extern size_t * TablePrefixSum64 (FlatArray<size_t> entrysize);
NETGEN_INLINE size_t * TablePrefixSum (FlatArray<unsigned int> entrysize)
{ return TablePrefixSum32 (entrysize); }
NETGEN_INLINE size_t * TablePrefixSum (FlatArray<int> entrysize)
{ return TablePrefixSum32 (FlatArray<unsigned> (entrysize.Size(), (unsigned int*)(int*)(entrysize.Addr(0)))); }
NETGEN_INLINE size_t * TablePrefixSum (FlatArray<std::atomic<int>> entrysize)
{ return TablePrefixSum32 (FlatArray<unsigned> (entrysize.Size(), (unsigned int*)(std::atomic<int>*)entrysize.Addr(0))); }
NETGEN_INLINE size_t * TablePrefixSum (FlatArray<size_t> entrysize)
{ return TablePrefixSum64 (entrysize); }
/**
A compact Table container.
A table contains size entries of variable size.
The entry sizes must be known at construction.
*/
template <class T>
class Table : public FlatTable<T>
{
protected:
using FlatTable<T>::size;
using FlatTable<T>::index;
using FlatTable<T>::data;
public:
///
NETGEN_INLINE Table () : FlatTable<T> (0,nullptr,nullptr) { ; }
/// Construct table of uniform entrysize
NETGEN_INLINE Table (size_t asize, size_t entrysize)
: FlatTable<T>( asize, new size_t[asize+1], new T[asize*entrysize] )
{
2019-08-30 11:28:08 +05:00
for (size_t i : IntRange(size+1))
2019-08-29 17:21:18 +05:00
index[i] = i*entrysize;
}
/// Construct table of variable entrysize
template <typename TI>
NETGEN_INLINE Table (FlatArray<TI> entrysize)
: FlatTable<T> (0, nullptr, nullptr)
{
size = entrysize.Size();
index = TablePrefixSum (entrysize);
size_t cnt = index[size];
data = new T[cnt];
}
explicit NETGEN_INLINE Table (const Table<T> & tab2)
: FlatTable<T>(0, nullptr, nullptr)
{
size = tab2.Size();
index = new size_t[size+1];
for (size_t i = 0; i <= size; i++)
index[i] = tab2.index[i];
size_t cnt = index[size];
data = new T[cnt];
for (size_t i = 0; i < cnt; i++)
data[i] = tab2.data[i];
}
NETGEN_INLINE Table (Table<T> && tab2)
: FlatTable<T>(0, nullptr, nullptr)
{
Swap (size, tab2.size);
Swap (index, tab2.index);
Swap (data, tab2.data);
}
NETGEN_INLINE Table & operator= (Table<T> && tab2)
{
Swap (size, tab2.size);
Swap (index, tab2.index);
Swap (data, tab2.data);
return *this;
}
/// Delete data
NETGEN_INLINE ~Table ()
{
delete [] data;
delete [] index;
}
/// Size of table
using FlatTable<T>::Size;
/// number of elements in all rows
NETGEN_INLINE size_t NElements() const { return index[size]; }
using FlatTable<T>::operator[];
};
/// Print table
template <class T>
inline ostream & operator<< (ostream & s, const Table<T> & table)
{
for (auto i : Range(table))
{
s << i << ":";
for (auto el : table[i])
s << " " << el;
s << "\n";
}
s << std::flush;
return s;
}
template <class T>
class TableCreator
{
protected:
int mode; // 1 .. cnt, 2 .. cnt entries, 3 .. fill table
std::atomic<size_t> nd;
Array<std::atomic<int>> cnt;
Table<T> table;
public:
TableCreator()
{ nd = 0; mode = 1; }
TableCreator (size_t acnt)
{ nd = acnt; SetMode(2); }
Table<T> MoveTable()
{
return std::move(table);
}
bool Done () { return mode > 3; }
void operator++(int) { SetMode (mode+1); }
int GetMode () const { return mode; }
void SetMode (int amode)
{
mode = amode;
if (mode == 2)
{
// cnt.SetSize(nd); // atomic has no copy
cnt = Array<std::atomic<int>> (nd);
for (auto & ci : cnt) ci.store (0, std::memory_order_relaxed);
}
if (mode == 3)
{
table = Table<T> (cnt);
// for (auto & ci : cnt) ci = 0;
for (auto & ci : cnt) ci.store (0, std::memory_order_relaxed);
// cnt = 0;
}
}
void SetSize (size_t _nd)
{
if (mode == 1)
nd = _nd;
else
{
if (nd != _nd)
throw Exception ("cannot change size of table-creator");
}
}
void Add (size_t blocknr, const T & data)
{
switch (mode)
{
case 1:
{
size_t oldval = nd;
while (blocknr+1>nd) {
nd.compare_exchange_weak (oldval, blocknr+1);
oldval = nd;
}
break;
}
case 2:
cnt[blocknr]++;
break;
case 3:
int ci = cnt[blocknr]++;
table[blocknr][ci] = data;
break;
}
}
void Add (size_t blocknr, IntRange range)
{
switch (mode)
{
case 1:
{
size_t oldval = nd;
while (blocknr+1>nd) {
nd.compare_exchange_weak (oldval, blocknr+1);
oldval = nd;
}
break;
}
case 2:
cnt[blocknr] += range.Size();
break;
case 3:
size_t ci = ( cnt[blocknr] += range.Size() ) - range.Size();
for (size_t j = 0; j < range.Size(); j++)
table[blocknr][ci+j] = range.First()+j;
break;
}
}
void Add (size_t blocknr, const FlatArray<int> & dofs)
{
switch (mode)
{
case 1:
{
size_t oldval = nd;
while (blocknr+1>nd) {
nd.compare_exchange_weak (oldval, blocknr+1);
oldval = nd;
}
break;
}
case 2:
cnt[blocknr] += dofs.Size();
break;
case 3:
size_t ci = ( cnt[blocknr] += dofs.Size() ) - dofs.Size();
for (size_t j = 0; j < dofs.Size(); j++)
table[blocknr][ci+j] = dofs[j];
break;
}
}
};
class NGCORE_API FilteredTableCreator : public TableCreator<int>
{
protected:
const BitArray* takedofs;
public:
FilteredTableCreator(const BitArray* atakedofs)
: TableCreator<int>(), takedofs(atakedofs) { };
FilteredTableCreator(int acnt, const BitArray* atakedofs)
: TableCreator<int>(acnt),takedofs(atakedofs) { };
void Add (size_t blocknr, int data);
void Add (size_t blocknr, IntRange range);
void Add (size_t blocknr, FlatArray<int> dofs);
};
/// Base class to generic DynamicTable.
class BaseDynamicTable
{
protected:
///
struct linestruct
{
///
int size;
///
int maxsize;
///
void * col;
};
///
Array<linestruct> data;
///
char * oneblock;
public:
///
NGCORE_API BaseDynamicTable (int size);
///
NGCORE_API BaseDynamicTable (const Array<int> & entrysizes, int elemsize);
///
NGCORE_API ~BaseDynamicTable ();
/// Changes Size of table to size, deletes data
NGCORE_API void SetSize (int size);
///
NGCORE_API void IncSize (int i, int elsize);
NGCORE_API void DecSize (int i);
};
/**
A dynamic table class.
A DynamicTable contains entries of variable size. Entry sizes can
be increased dynamically.
*/
template <class T>
class DynamicTable : public BaseDynamicTable
{
public:
/// Creates table of size size
DynamicTable (int size = 0)
: BaseDynamicTable (size) { ; }
/// Creates table with a priori fixed entry sizes.
DynamicTable (const Array<int> & entrysizes)
: BaseDynamicTable (entrysizes, sizeof(T)) { ; }
/// Inserts element acont into row i. Does not test if already used.
void Add (int i, const T & acont)
{
if (data[i].size == data[i].maxsize)
IncSize (i, sizeof (T));
else
data[i].size++;
static_cast<T*> (data[i].col) [data[i].size-1] = acont;
}
/// Inserts element acont into row i, iff not yet exists.
void AddUnique (int i, const T & cont)
{
int es = EntrySize (i);
int * line = const_cast<int*> (GetLine (i));
for (int j = 0; j < es; j++)
if (line[j] == cont)
return;
Add (i, cont);
}
/// Inserts element acont into row i. Does not test if already used.
void AddEmpty (int i)
{
IncSize (i, sizeof (T));
}
/** Set the nr-th element in the i-th row to acont.
Does not check for overflow. */
void Set (int i, int nr, const T & acont)
{ static_cast<T*> (data[i].col)[nr] = acont; }
/** Returns the nr-th element in the i-th row.
Does not check for overflow. */
const T & Get (int i, int nr) const
{ return static_cast<T*> (data[i].col)[nr]; }
/** Returns pointer to the first element in row i. */
const T * GetLine (int i) const
{ return static_cast<T*> (data[i].col); }
/// Returns size of the table.
int Size () const
{ return data.Size(); }
/// Returns size of the i-th row.
int EntrySize (int i) const
{ return data[i].size; }
///
void DecEntrySize (int i)
{ DecSize(i); }
/// Access entry i
FlatArray<T> operator[] (int i)
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
/*
typedef const FlatArray<T> ConstFlatArray;
/// Access entry i
ConstFlatArray operator[] (int i) const
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
*/
FlatArray<T> operator[] (int i) const
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
};
/// Print table
template <class T>
inline ostream & operator<< (ostream & s, const DynamicTable<T> & table)
{
for (int i = 0; i < table.Size(); i++)
{
s << i << ":";
for (int j = 0; j < table[i].Size(); j++)
s << " " << table[i][j];
s << "\n";
}
s << std::flush;
return s;
}
typedef DynamicTable<int> IntTable;
} // namespace ngcore
#endif // NETGEN_CORE_TABLE_HPP