#ifndef NGARRAY_HPP_INCLUDED #define NGARRAY_HPP_INCLUDED /**************************************************************************/ /* File: ngarray.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include namespace netgen { using namespace ngcore; // template class IndirectArray; template class NgIndirectArray; template class ArrayRangeIterator { TSIZE ind; public: ArrayRangeIterator (TSIZE ai) : ind(ai) { ; } ArrayRangeIterator operator++ (int) { return ind++; } ArrayRangeIterator operator++ () { return ++ind; } TSIZE operator*() const { return ind; } bool operator != (ArrayRangeIterator d2) { return ind != d2.ind; } }; /// a range of integers template class T_Range { T first, next; public: T_Range (T f, T n) : first(f), next(n) {;} T Size() const { return next-first; } T operator[] (T i) const { return first+i; } bool Contains (T i) const { return ((i >= first) && (i < next)); } T_Range Modify (int inc_begin, int inc_end) const { return T_Range(first+inc_begin, next+inc_end); } ArrayRangeIterator begin() const { return first; } ArrayRangeIterator end() const { return next; } }; template class NgFlatArray; template class ArrayIterator { NgFlatArray ar; TIND ind; public: ArrayIterator (NgFlatArray aar, TIND ai) : ar(aar), ind(ai) { ; } ArrayIterator operator++ (int) { return ArrayIterator(ar, ind++); } ArrayIterator operator++ () { return ArrayIterator(ar, ++ind); } T operator*() const { return ar[ind]; } T & operator*() { return ar[ind]; } bool operator != (ArrayIterator d2) { return ind != d2.ind; } bool operator == (ArrayIterator d2) { return ind == d2.ind; } }; /** A simple array container. NgArray represented by size and data-pointer. No memory allocation and deallocation, must be provided by user. Helper functions for printing. Optional range check by macro RANGE_CHECK */ template class NgFlatArray { protected: /// the size size_t size; /// the data T * data; public: typedef T TELEM; using index_type = TIND; /// provide size and memory NgFlatArray (size_t asize, T * adata) : size(asize), data(adata) { ; } /// the size size_t Size() const { return size; } ArrayIterator begin() const { return ArrayIterator (*this, BASE); } ArrayIterator end() const { return ArrayIterator (*this, BASE+size); } // TIND Begin() const { return TIND(BASE); } // TIND End() const { return TIND(size+BASE); } T_Range Range() const { return T_Range(BASE, size+BASE); } [[deprecated("Use *Range().begin() instead")]] auto Begin() const { return *Range().begin(); } [[deprecated("Use *Range().end() instead")]] auto End() const { return *Range().end(); } /// Access array. BASE-based T & operator[] (TIND i) const { NETGEN_CHECK_RANGE(i,BASE,size+BASE); return data[i-BASE]; } template NgIndirectArray > operator[] (const NgFlatArray & ia) const { return NgIndirectArray > (*this, ia); } /// Access array, one-based (old fashioned) T & Elem (int i) { NETGEN_CHECK_RANGE(i,1,size+1); return ((T*)data)[i-1]; } /// Access array, one-based (old fashioned) // [[deprecated("Use operator[] instead")]] const T & Get (int i) const { NETGEN_CHECK_RANGE(i,1,size+1); return ((const T*)data)[i-1]; } /// Access array, one-based (old fashioned) void Set (int i, const T & el) { NETGEN_CHECK_RANGE(i,1,size+1); ((T*)data)[i-1] = el; } /// access first element T & First () const { NETGEN_CHECK_RANGE(0,0,size); return data[0]; } /// access last element. check by macro CHECK_RANGE T & Last () const { NETGEN_CHECK_RANGE(size-1,0,size); return data[size-1]; } /// Fill array with value val NgFlatArray & operator= (const T & val) { for (int i = 0; i < size; i++) data[i] = val; return *this; } /// takes range starting from position start of end-start elements const NgFlatArray Range (TIND start, TIND end) { return NgFlatArray (end-start, data+start); } /// first position of element elem, returns -1 if element not contained in array TIND Pos(const T & elem) const { TIND pos = -1; for(TIND i=0; pos==-1 && i < this->size; i++) if(elem == data[i]) pos = i; return pos; } /// does the array contain element elem ? bool Contains(const T & elem) const { return ( Pos(elem) >= 0 ); } operator ngcore::FlatArray () const { static_assert (BASE==0); return ngcore::FlatArray(size, data); } }; // print array template inline ostream & operator<< (ostream & s, const NgFlatArray & a) { // for (TIND i = a.Begin(); i < a.End(); i++) for (auto i : a.Range()) s << i << ": " << a[i] << endl; return s; } /** Dynamic array container. NgArray is an automatically increasing array container. The allocated memory doubles on overflow. Either the container takes care of memory allocation and deallocation, or the user provides one block of data. */ template class NgArray : public NgFlatArray { protected: using NgFlatArray::size; using NgFlatArray::data; /// physical size of array size_t allocsize = 0; /// memory is responsibility of container bool ownmem; public: /// Generate array of logical and physical size asize explicit NgArray() : NgFlatArray (0, NULL) { allocsize = 0; ownmem = 1; } explicit NgArray(size_t asize) : NgFlatArray (asize, asize ? new T[asize] : nullptr) { allocsize = asize; ownmem = (asize == 0) ? 0 : 1; } /// Generate array in user data NgArray(TIND asize, T* adata) : NgFlatArray (asize, adata) { allocsize = asize; ownmem = 0; } /// array copy explicit NgArray (const NgArray & a2) : NgFlatArray (a2.Size(), a2.Size() ? new T[a2.Size()] : 0) { allocsize = size; ownmem = 1; for (TIND i = BASE; i < size+BASE; i++) (*this)[i] = a2[i]; } /// array move NgArray (NgArray && a2) : NgFlatArray (a2.size, a2.data), allocsize(a2.allocsize), ownmem(a2.ownmem) { a2.size = 0; a2.data = nullptr; a2.allocsize = 0; a2.ownmem = false; } /// if responsible, deletes memory ~NgArray() { if (ownmem) delete [] data; } /// Change logical size. If necessary, do reallocation. Keeps contents. void SetSize(size_t nsize) { if (nsize > allocsize) ReSize (nsize); size = nsize; } void SetSize0() { size = 0; } /// Change physical size. Keeps logical size. Keeps contents. void SetAllocSize (size_t nallocsize) { if (nallocsize > allocsize) ReSize (nallocsize); } /// Add element at end of array. reallocation if necessary. void Append (const T & el) { if (size == allocsize) ReSize (size+1); data[size] = el; size++; // return size; } template void Append (NgFlatArray a2) { if (size+a2.Size() > allocsize) ReSize (size+a2.Size()); for (int i = 0; i < a2.Size(); i++) data[size+i] = a2[i+B2]; size += a2.Size(); } /// Delete element i (0-based). Move last element to position i. void Delete (TIND i) { NETGEN_CHECK_RANGE(i,0,size); data[i] = std::move(data[size-1]); size--; // DeleteElement (i+1); } /// Delete element i (1-based). Move last element to position i. void DeleteElement (TIND i) { NETGEN_CHECK_RANGE(i,1,size+1); data[i-1] = std::move(data[size-1]); size--; } /// Delete last element. void DeleteLast () { size--; } /// Deallocate memory void DeleteAll () { if (ownmem) delete [] data; data = 0; size = allocsize = 0; } /// Fill array with val NgArray & operator= (const T & val) { NgFlatArray::operator= (val); return *this; } /// array copy NgArray & operator= (const NgArray & a2) { SetSize (a2.Size()); for (TIND i (BASE); i < size+BASE; i++) (*this)[i] = a2[i]; return *this; } /// array copy NgArray & operator= (const NgFlatArray & a2) { SetSize (a2.Size()); for (TIND i = BASE; i < size+BASE; i++) (*this)[i] = a2[i]; return *this; } NgArray & operator= (NgArray && a2) { ngcore::Swap (data, a2.data); ngcore::Swap (size, a2.size); ngcore::Swap (allocsize, a2.allocsize); ngcore::Swap (ownmem, a2.ownmem); return *this; } T * Release() { ownmem = false; return data; } // Only provide this function if T is archivable template auto DoArchive(ARCHIVE& archive) -> typename std::enable_if_t, void> { if(archive.Output()) archive << size; else { size_t s; archive & s; SetSize(s); } archive.Do(data, size); } private: /// resize array, at least to size minsize. copy contents void ReSize (size_t minsize) { size_t nsize = 2 * allocsize; if (nsize < minsize) nsize = minsize; if (data) { T * p = new T[nsize]; size_t mins = (nsize < size) ? nsize : size; if constexpr(std::is_trivially_copyable::value) memcpy (p, data, sizeof(T)*mins); else for (size_t i = 0; i < mins; i++) p[i] = std::move(data[i]); if (ownmem) delete [] data; ownmem = 1; data = p; } else { data = new T[nsize]; ownmem = 1; } allocsize = nsize; } }; template class NgArrayMem : public NgArray { using NgArray::size; using NgArray::data; using NgArray::ownmem; T mem[S]; // Intel C++ calls dummy constructor // char mem[S*sizeof(T)]; // double mem[(S*sizeof(T)+7) / 8]; public: /// Generate array of logical and physical size asize explicit NgArrayMem(size_t asize = 0) : NgArray (S, static_cast (static_cast(&mem[0]))) { size = asize; if (asize > S) { data = new T[asize]; ownmem = 1; } // SetSize (asize); } NgArrayMem & operator= (const T & val) { NgArray::operator= (val); return *this; } /// array copy NgArrayMem & operator= (const NgFlatArray & a2) { this->SetSize (a2.Size()); for (size_t i = 0; i < size; i++) (*this)[i] = a2[i]; return *this; } }; /* template class IndirectArray { const NgFlatArray & array; const NgFlatArray & ia; public: IndirectArray (const NgFlatArray & aa, const NgFlatArray & aia) : array(aa), ia(aia) { ; } int Size() const { return ia.Size(); } const T & operator[] (int i) const { return array[ia[i]]; } }; */ template class NgIndirectArray { const TA1 & array; const TA2 & ia; public: NgIndirectArray (const TA1 & aa, const TA2 & aia) : array(aa), ia(aia) { ; } int Size() const { return ia.Size(); } [[deprecated("Use *Range().begin() instead")]] int Begin() const { return ia.Begin(); } [[deprecated("Use *Range().end() instead")]] int End() const { return ia.End(); } const typename TA1::TELEM & operator[] (int i) const { return array[ia[i]]; } auto Range() const { return ia.Range(); } // auto begin() const { return ia.begin(); } // auto end() const { return ia.end(); } }; template inline ostream & operator<< (ostream & s, const NgIndirectArray & ia) { for (int i = ia.Begin(); i < ia.End(); i++) s << i << ": " << ia[i] << endl; return s; } /* /// template class MoveableArray { int size; int allocsize; DynamicMem data; public: MoveableArray() { size = allocsize = 0; data.SetName ("MoveableArray"); } MoveableArray(int asize) : size(asize), allocsize(asize), data(asize) { ; } ~MoveableArray () { ; } int Size() const { return size; } void SetSize(int nsize) { if (nsize > allocsize) { data.ReAlloc (nsize); allocsize = nsize; } size = nsize; } void SetAllocSize (int nallocsize) { data.ReAlloc (nallocsize); allocsize = nallocsize; } /// T & operator[] (int i) { return ((T*)data)[i-BASE]; } /// const T & operator[] (int i) const { return ((const T*)data)[i-BASE]; } /// T & Elem (int i) { return ((T*)data)[i-1]; } /// const T & Get (int i) const { return ((const T*)data)[i-1]; } /// void Set (int i, const T & el) { ((T*)data)[i-1] = el; } /// T & Last () { return ((T*)data)[size-1]; } /// const T & Last () const { return ((const T*)data)[size-1]; } /// int Append (const T & el) { if (size == allocsize) { SetAllocSize (2*allocsize+1); } ((T*)data)[size] = el; size++; return size; } /// void Delete (int i) { DeleteElement (i+1); } /// void DeleteElement (int i) { ((T*)data)[i-1] = ((T*)data)[size-1]; size--; } /// void DeleteLast () { size--; } /// void DeleteAll () { size = allocsize = 0; data.Free(); } /// void PrintMemInfo (ostream & ost) const { ost << Size() << " elements of size " << sizeof(T) << " = " << Size() * sizeof(T) << endl; } MoveableArray & operator= (const T & el) { for (int i = 0; i < size; i++) ((T*)data)[i] = el; return *this; } MoveableArray & Copy (const MoveableArray & a2) { SetSize (a2.Size()); for (int i = 0; i < this->size; i++) data[i] = a2.data[i]; return *this; } /// array copy MoveableArray & operator= (const MoveableArray & a2) { return Copy(a2); } void SetName (const char * aname) { data.SetName(aname); } private: /// //MoveableArray & operator= (MoveableArray &); //??? /// //MoveableArray (const MoveableArray &); //??? }; template inline ostream & operator<< (ostream & ost, MoveableArray & a) { for (int i = 0; i < a.Size(); i++) ost << i << ": " << a[i] << endl; return ost; } */ /// bubble sort array template inline void BubbleSort (const NgFlatArray & data) { for (int i = 0; i < data.Size(); i++) for (int j = i+1; j < data.Size(); j++) if (data[i] > data[j]) { T hv = data[i]; data[i] = data[j]; data[j] = hv; } } /// bubble sort array template inline void BubbleSort (NgFlatArray & data, NgFlatArray & index) { for (int i = 0; i < data.Size(); i++) for (int j = i+1; j < data.Size(); j++) if (data[i] > data[j]) { T hv = data[i]; data[i] = data[j]; data[j] = hv; S hvs = index[i]; index[i] = index[j]; index[j] = hvs; } } template void QuickSortRec (NgFlatArray & data, NgFlatArray & index, int left, int right) { int i = left; int j = right; T midval = data[(left+right)/2]; do { while (data[i] < midval) i++; while (midval < data[j]) j--; if (i <= j) { ngcore::Swap (data[i], data[j]); ngcore::Swap (index[i], index[j]); i++; j--; } } while (i <= j); if (left < j) QuickSortRec (data, index, left, j); if (i < right) QuickSortRec (data, index, i, right); } template void QuickSort (NgFlatArray & data, NgFlatArray & index) { if (data.Size() > 1) QuickSortRec (data, index, 0, data.Size()-1); } template void Intersection (const NgFlatArray & in1, const NgFlatArray & in2, NgArray & out) { out.SetSize(0); for(int i=0; i void Intersection (const NgFlatArray & in1, const NgFlatArray & in2, const NgFlatArray & in3, NgArray & out) { out.SetSize(0); for(int i=0; i