#ifndef NETGEN_CORE_ARRAY_HPP #define NETGEN_CORE_ARRAY_HPP /**************************************************************************/ /* File: array.hpp */ /* Author: Joachim Schoeberl */ /* Date: 01. Jun. 95 */ /**************************************************************************/ #include #include #include "exception.hpp" #include "logging.hpp" // for logger #include "ngcore_api.hpp" // for NGCORE_API #include "type_traits.hpp" // for all_of_tmpl #include "localheap.hpp" #include "memtracer.hpp" #include "utils.hpp" namespace ngcore { using std::ostream; template class Tuple { public: int Size() const { return 0; } }; template class Tuple : Tuple { typedef Tuple BASE; HEAD head; public: Tuple () { ; } Tuple (HEAD h, TAIL ... t) : Tuple (t...), head(h) { ; } HEAD Head() const { return head; } Tuple Tail() const { return *this; } int Size() const { return BASE::Size()+1; } }; template ostream & operator<< (ostream & ost, Tuple /* tup */) { return ost; } template ostream & operator<< (ostream & ost, Tuple tup) { ost << tup.Head() << ", " << tup.Tail(); return ost; } template Tuple MakeTuple (ARGS ... args) { return Tuple (args...); } template class AOWrapperIterator { const AO & ao; size_t ind; public: NETGEN_INLINE AOWrapperIterator (const AO & aao, size_t ai) : ao(aao), ind(ai) { ; } NETGEN_INLINE AOWrapperIterator operator++ (int) { return AOWrapperIterator(ao, ind++); } NETGEN_INLINE AOWrapperIterator& operator++ () { ++ind; return *this; } NETGEN_INLINE auto operator*() const -> decltype(ao[ind]) { return ao[ind]; } NETGEN_INLINE auto operator*() -> decltype(ao[ind]) { return ao[ind]; } NETGEN_INLINE bool operator != (AOWrapperIterator d2) { return ind != d2.ind; } NETGEN_INLINE bool operator == (AOWrapperIterator d2) { return ind == d2.ind; } }; /* Some class which can be treated as array */ template // , typename TA = T> class BaseArrayObject { public: NETGEN_INLINE BaseArrayObject() { ; } NETGEN_INLINE const T & Spec() const { return static_cast (*this); } NETGEN_INLINE size_t Size() const { return Spec().Size(); } template NETGEN_INLINE bool Contains(const T2 & el) const { for (size_t i = 0; i < Size(); i++) if (Spec()[i] == el) return true; return false; } static constexpr size_t ILLEGAL_POSITION = size_t(-1); template NETGEN_INLINE size_t Pos(const T2 & el) const { for (size_t i = 0; i < Size(); i++) if (Spec()[i] == el) return i; return ILLEGAL_POSITION; } template NETGEN_INLINE size_t PosSure(const T2 & el) const { for (size_t i = 0; ; i++) if (Spec()[i] == el) return i; } // NETGEN_INLINE auto & operator[] (size_t i) { return Spec()[i]; } NETGEN_INLINE auto operator[] (size_t i) const { return Spec()[i]; } // NETGEN_INLINE auto begin() const { return Spec().begin(); } // NETGEN_INLINE auto end() const { return Spec().end(); } NETGEN_INLINE auto begin () const { return AOWrapperIterator (*this, 0); } NETGEN_INLINE auto end () const { return AOWrapperIterator (*this, Size()); } }; template class AOWrapper : public BaseArrayObject> { T ar; public: NETGEN_INLINE AOWrapper (T aar) : ar(aar) { ; } NETGEN_INLINE operator T () const { return ar; } NETGEN_INLINE size_t Size() const { return ar.Size(); } NETGEN_INLINE auto operator[] (size_t i) { return ar[i]; } NETGEN_INLINE auto operator[] (size_t i) const { return ar[i]; } NETGEN_INLINE AOWrapperIterator begin () const { return AOWrapperIterator (*this, 0); } NETGEN_INLINE AOWrapperIterator end () const { return AOWrapperIterator (*this, Size()); } }; template NETGEN_INLINE AOWrapper ArrayObject (const T & ar) { return AOWrapper (ar); } template NETGEN_INLINE AOWrapper ArrayObject (T && ar) { return AOWrapper (ar); } template auto ArrayObject (size_t s, FUNC f) { class Dummy { size_t s; FUNC f; public: Dummy (size_t _s, FUNC _f) : s(_s), f(_f) { ; } size_t Size() const { return s; } auto operator[] (size_t i) const { return f(i); } }; return ArrayObject(Dummy(s,f)); } template auto Substitute (const BaseArrayObject & ao, FUNC f) { return ArrayObject(ao.Size(), [&ao,f] (size_t i) { return f(ao[i]); }); } /** nothing more but a new type for a C array. return value for Addr - operator of array */ template class CArray { protected: /// the data T * data; public: /// initialize array NETGEN_INLINE CArray () { data = 0; } /// provide size and memory NETGEN_INLINE CArray (T * adata) : data(adata) { ; } /// Access array NETGEN_INLINE T & operator[] (size_t i) const { return data[i]; } NETGEN_INLINE operator T* () const { return data; } }; template constexpr T IndexBASE () { return T(0); } class IndexFromEnd { ptrdiff_t i; public: constexpr IndexFromEnd (ptrdiff_t ai) : i(ai) { } IndexFromEnd operator+ (ptrdiff_t inc) const { return i+inc; } IndexFromEnd operator- (ptrdiff_t dec) const { return i-dec; } // operator ptrdiff_t () const { return i; } ptrdiff_t Value() const { return i; } }; constexpr IndexFromEnd END(0); template class FlatArray; template class ArrayIterator { FlatArray ar; IndexType ind; public: NETGEN_INLINE ArrayIterator (FlatArray aar, IndexType ai) : ar(aar), ind(ai) { ; } NETGEN_INLINE ArrayIterator operator++ (int) { return ArrayIterator(ar, ind++); } NETGEN_INLINE ArrayIterator operator++ () { return ArrayIterator(ar, ++ind); } // NETGEN_INLINE const TELEM & operator*() const { return ar[ind]; } // NETGEN_INLINE TELEM & operator*() { return ar[ind]; } NETGEN_INLINE auto operator*() const -> decltype(ar[ind]) { return ar[ind]; } NETGEN_INLINE auto operator*() -> decltype(ar[ind]) { return ar[ind]; } NETGEN_INLINE bool operator != (ArrayIterator d2) { return ind != d2.ind; } NETGEN_INLINE bool operator == (ArrayIterator d2) { return ind == d2.ind; } }; template class ArrayRangeIterator { TSIZE ind; public: NETGEN_INLINE ArrayRangeIterator (TSIZE ai) : ind(ai) { ; } NETGEN_INLINE ArrayRangeIterator operator++ (int) { return ind++; } NETGEN_INLINE ArrayRangeIterator operator++ () { return ++ind; } NETGEN_INLINE TSIZE operator*() const { return ind; } NETGEN_INLINE TSIZE Index() { return ind; } NETGEN_INLINE operator TSIZE () const { return ind; } NETGEN_INLINE bool operator != (ArrayRangeIterator d2) { return ind != d2.ind; } NETGEN_INLINE bool operator == (ArrayRangeIterator d2) { return ind == d2.ind; } }; /// a range of integers template class T_Range : public BaseArrayObject > { T first, next; public: NETGEN_INLINE T_Range () { ; } NETGEN_INLINE T_Range (T n) : first(0), next(n) {;} NETGEN_INLINE T_Range (T f, T n) : first(f), next(n) {;} template NETGEN_INLINE T_Range(T_Range r2) : first(r2.First()), next(r2.Next()) { ; } NETGEN_INLINE T First() const { return first; } NETGEN_INLINE T Next() const { return next; } NETGEN_INLINE T & First() { return first; } NETGEN_INLINE T & Next() { return next; } NETGEN_INLINE auto Size() const { return next-first; } NETGEN_INLINE T operator[] (size_t i) const { return first+i; } NETGEN_INLINE bool Contains (T i) const { return ((i >= first) && (i < next)); } NETGEN_INLINE T_Range Modify(int inc_beg, int inc_end) const { return T_Range(first+inc_beg, next+inc_end); } NETGEN_INLINE ArrayRangeIterator begin() const { return first; } NETGEN_INLINE ArrayRangeIterator end() const { return next; } T_Range Split (size_t nr, int tot) const { T diff = next-first; return T_Range (first + nr * diff / tot, first + (nr+1) * diff / tot); } // NETGEN_INLINE operator IntRange () const { return IntRange(first,next); } }; using IntRange = T_Range; template NETGEN_INLINE T_Range Range (T a, T b) { return T_Range(a,b); } template NETGEN_INLINE auto Range (const T& ao) -> typename std::enable_if, decltype(std::declval().Range())>::type { return ao.Range(); } template NETGEN_INLINE T_Range Range_impl (T n, std::true_type) { return T_Range (0, n); } template NETGEN_INLINE auto Range_impl (const TA & ao, std::false_type) -> T_Range> { return T_Range> (IndexBASE>(), IndexBASE>() + index_type(ao.Size())); } /* Range(obj) will create a range in using the following steps: * if obj is an integral type it will create T_Range(0, obj) * if obj has a function Range() it will return obj.Range() * if obj has a typedef index_type it will return T_Range(IndexBASE(), IndexBASE() + index_type(obj.Size())) * else it will return T_Range (0, obj.Size()) */ template auto Range(const T & x) -> typename std::enable_if || !has_range, decltype(Range_impl(x, std::is_integral()))>::type { return Range_impl(x, std::is_integral()); } NETGEN_INLINE IntRange operator+ (const IntRange & range, int shift) { return IntRange (range.First()+shift, range.Next()+shift); } NETGEN_INLINE IntRange operator+ (int shift, const IntRange & range) { return IntRange (range.First()+shift, range.Next()+shift); } NETGEN_INLINE IntRange operator* (int scale, const IntRange & range) { return IntRange (scale*range.First(), scale*range.Next()); } NETGEN_INLINE IntRange operator* (const IntRange & range, int scale) { return IntRange (scale*range.First(), scale*range.Next()); } template inline ostream & operator<< (ostream & s, T_Range ir) { s << "[" << ir.First() << "," << ir.Next() << ")"; return s; } template ostream & operator<< (ostream & ost, Tuple tup) { ost << tup.Head() << ", " << tup.Tail(); return ost; } template inline ostream & operator<< (ostream & ost, const BaseArrayObject & array) { for (auto i : Range(array.Size())) ost << i << ":" << array[i] << std::endl; return ost; } template class IndirectArray : public BaseArrayObject > { FlatArray ba; const INDEX_ARRAY & ia; public: NETGEN_INLINE IndirectArray (FlatArray aba, const INDEX_ARRAY & aia) : ba(aba), ia(aia) { ; } NETGEN_INLINE size_t Size() const { return ia.Size(); } NETGEN_INLINE T & operator[] (size_t i) const { return ba[ia[i]]; } // NETGEN_INLINE T & operator[] (size_t i) { return ba[ia[i]]; } NETGEN_INLINE IndirectArray operator= (const T & val) { for (auto i : Range(Size())) (*this)[i] = val; return IndirectArray (ba, ia); } template NETGEN_INLINE IndirectArray operator= (const BaseArrayObject & a2) { for (auto i : Range(Size())) (*this)[i] = a2[i]; return IndirectArray (ba, ia); } NETGEN_INLINE AOWrapperIterator begin() const { return { *this, 0 }; } NETGEN_INLINE AOWrapperIterator end() const { return { *this, Size() }; } }; /** A simple array container. Array 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 NETGEN_CHECK_RANGE */ template class FlatArray : public BaseArrayObject > { protected: static constexpr IndexType BASE = IndexBASE(); /// the size size_t size = 0; /// the data T * __restrict data = nullptr; public: typedef T value_type; typedef IndexType index_type; using BaseArrayObject::ILLEGAL_POSITION; /// initialize array NETGEN_INLINE FlatArray () = default; // { ; } // size = 0; data = 0; } /// copy constructor allows size-type conversion NETGEN_INLINE FlatArray (const FlatArray & a2) = default; // : size(a2.Size()), data(a2.data) { ; } /// provide size and memory NETGEN_INLINE FlatArray (size_t asize, T * adata) : size(asize), data(adata) { ; } /// memory from local heap NETGEN_INLINE FlatArray(size_t asize, Allocator & lh) : size(asize), data(new (lh) T[asize]) { ; } NETGEN_INLINE FlatArray(size_t asize, LocalHeap & lh) : size(asize), data (lh.Alloc (asize)) { ; } /// the size NETGEN_INLINE size_t Size() const { return size; } /// the data NETGEN_INLINE T* Data() const { return data; } /// Fill array with value val NETGEN_INLINE const FlatArray & operator= (const T & val) const { size_t hsize = size; T * hdata = data; for (size_t i = 0; i < hsize; i++) hdata[i] = val; return *this; } /// copies array NETGEN_INLINE const FlatArray & operator= (const FlatArray & a2) const { size_t hsize = size; T * hdata = data; for (size_t i = 0; i < hsize; i++) hdata[i] = a2.data[i]; return *this; } template NETGEN_INLINE const FlatArray & operator= (const BaseArrayObject & a2) const { size_t hsize = size; T * hdata = data; auto p2 = a2.begin(); for (size_t i = 0; i < hsize; i++, p2++) hdata[i] = *p2; return *this; } template ::value>> NETGEN_INLINE const FlatArray & operator= (const T2 & func) const { for (size_t i = 0; i < size; i++) data[i] = func(i+BASE); return *this; } // template // const FlatArray operator= (ParallelValue val); // template // const FlatArray operator= (ParallelFunction val); /// copies pointers NETGEN_INLINE const FlatArray & Assign (const FlatArray & a2) { size = a2.size; data = a2.data; return *this; } /// assigns memory from local heap NETGEN_INLINE const FlatArray & Assign (size_t asize, LocalHeap & lh) { size = asize; data = lh.Alloc (asize); return *this; } /// Access array. range check by macro NETGEN_CHECK_RANGE NETGEN_INLINE T & operator[] (IndexType i) const { NETGEN_CHECK_RANGE(i,BASE,size+BASE); return data[i-BASE]; } NETGEN_INLINE T_Range Range () const { return T_Range (BASE, size+BASE); } NETGEN_INLINE const CArray Addr (size_t pos) const { return CArray (data+pos-BASE); } // const CArray operator+ (int pos) // { return CArray (data+pos); } NETGEN_INLINE T * operator+ (size_t pos) const { return data+pos; } /// access last element. check by macro NETGEN_CHECK_RANGE T & Last () const { NETGEN_CHECK_RANGE(size-1,0,size); return data[size-1]; } /// takes sub-array starting from position pos NETGEN_INLINE const FlatArray Part (size_t pos) { return FlatArray (size-pos, data+pos); } /// takes subsize elements starting from position pos NETGEN_INLINE const FlatArray Part (size_t pos, size_t subsize) { return FlatArray (subsize, data+pos); } /// takes range starting from position start of end-start elements NETGEN_INLINE FlatArray Range (size_t start, size_t end) const { return FlatArray (end-start, data+start); } /// takes range starting from position start of end-start elements NETGEN_INLINE FlatArray Range (size_t start, IndexFromEnd indend) const { return this->Range(start, size_t(Size()+indend.Value())); } /// takes range starting from position start of end-start elements NETGEN_INLINE FlatArray Range (T_Range range) const { return FlatArray (range.Size(), data+range.First()); } /// takes range starting from position start of end-start elements NETGEN_INLINE const FlatArray operator[] (T_Range range) const { return FlatArray (range.Size(), data+range.First()); } template auto operator[] (const BaseArrayObject & ind_array) const { return IndirectArray > (*this, ind_array); } /// first position of element elem, returns -1 if element not contained in array NETGEN_INLINE size_t Pos(const T & el) const { for (size_t i = 0; i < Size(); i++) if (data[i] == el) return i; return ILLEGAL_POSITION; } /// does the array contain element elem ? NETGEN_INLINE bool Contains(const T & elem) const { return Pos(elem) != ILLEGAL_POSITION; } //auto begin() const { return ArrayIterator (*this, BASE); } // auto end() const { return ArrayIterator (*this, size+BASE); } NETGEN_INLINE auto begin() const { return data; } NETGEN_INLINE auto end() const { return data+Size(); } }; template FlatArray View (FlatArray fa) { return fa; } template auto Max (FlatArray array, T max = std::numeric_limits::min()) -> T { for (auto & v : array) if (v > max) max = v; return max; } template auto Min (FlatArray array, T min = std::numeric_limits::max()) -> T { for (auto & v : array) if (v < min) min = v; return min; } /// print array template inline ostream & operator<< (ostream & s, const FlatArray & a) { for (auto i : a.Range()) s << i << ": " << a[i] << "\n"; return s; } /// have arrays the same contents ? template inline bool operator== (const FlatArray & a1, const FlatArray & a2) { if (a1.Size () != a2.Size()) return 0; for (size_t i = 0; i < a1.Size(); i++) if (a1[i] != a2[i]) return false; return true; } template inline bool operator!= (const FlatArray & a1, const FlatArray & a2) { return !(a1==a2); } /** Dynamic array container. Array 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 Array : public FlatArray { protected: /// physical size of array size_t allocsize; /// that's the data we have to delete, nullptr for not owning the memory T * mem_to_delete; using FlatArray::size; using FlatArray::data; using FlatArray::BASE; public: using index_type = typename FlatArray::index_type; /// Generate array of logical and physical size asize NETGEN_INLINE explicit Array() : FlatArray (0, nullptr) { allocsize = 0; mem_to_delete = nullptr; } NETGEN_INLINE explicit Array(size_t asize) : FlatArray (asize, new T[asize]) { allocsize = asize; mem_to_delete = data; } /// Generate array in user data NETGEN_INLINE Array(size_t asize, T* adata, bool ownMemory = false) : FlatArray (asize, adata) { allocsize = asize; if(ownMemory) mem_to_delete = adata; else mem_to_delete = nullptr; } /// Generate array in user data template NETGEN_INLINE Array(size_t asize, ALLOCATOR & lh) : FlatArray (asize, lh) { allocsize = asize; mem_to_delete = nullptr; } NETGEN_INLINE Array (Array && a2) { mt.Swap(sizeof(T) * allocsize, a2.mt, sizeof(T) * a2.allocsize); size = a2.size; data = a2.data; allocsize = a2.allocsize; mem_to_delete = a2.mem_to_delete; a2.size = 0; a2.allocsize = 0; a2.data = nullptr; a2.mem_to_delete = nullptr; } /// array copy NETGEN_INLINE explicit Array (const Array & a2) : FlatArray (a2.Size(), a2.Size() ? new T[a2.Size()] : nullptr) { static_assert(std::is_copy_assignable::value, "cannot copy-construct Array"); // if constexpr (std::is_copy_assignable::value) { allocsize = size; mem_to_delete = data; for (size_t i = 0; i < size; i++) data[i] = a2.data[i]; } // else // throw Exception(std::string("cannot copy-construct Array of type ") + typeid(T).name()); } template explicit Array (const BaseArrayObject & a2) : FlatArray (a2.Size(), a2.Size() ? new T[a2.Size()] : nullptr) { allocsize = size; mem_to_delete = data; /* for (size_t i = 0; i < size; i++) data[i] = a2[i]; */ auto p2 = a2.begin(); for (size_t i = 0; i < size; i++, p2++) data[i] = *p2; } Array (std::initializer_list list) : FlatArray (list.size(), list.size() ? new T[list.size()] : NULL) { allocsize = size; mem_to_delete = data; size_t cnt = 0; for (auto val : list) data[cnt++] = val; } /// array merge-copy explicit Array (const Array & a2, const Array & a3) : FlatArray (a2.Size()+a3.Size(), a2.Size()+a3.Size() ? new T[a2.Size()+a3.Size()] : 0) { allocsize = size; mem_to_delete = data; for(size_t i = 0; i < a2.Size(); i++) data[i] = a2[i]; for (size_t i = a2.Size(), j=0; i < size; i++,j++) data[i] = a3[j]; } /// if responsible, deletes memory NETGEN_INLINE ~Array() { if(mem_to_delete) mt.Free(sizeof(T)*allocsize); delete [] mem_to_delete; } // 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); } /// we tell the compiler that there is no need for deleting the array .. NETGEN_INLINE void NothingToDelete () { mem_to_delete = nullptr; } /// Change logical size. If necessary, do reallocation. Keeps contents. NETGEN_INLINE void SetSize(size_t nsize) { if (nsize > allocsize) ReSize (nsize); size = nsize; } /// NETGEN_INLINE void SetSize0() { size = 0; } /// Change physical size. Keeps logical size. Keeps contents. NETGEN_INLINE void SetAllocSize (size_t nallocsize) { if (nallocsize > allocsize) ReSize (nallocsize); } /// Change physical size. Keeps logical size. Keeps contents. NETGEN_INLINE size_t AllocSize () const { return allocsize; } /// assigns memory from local heap NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh) { if(mem_to_delete) mt.Free(sizeof(T)*allocsize); delete [] mem_to_delete; size = allocsize = asize; data = lh.Alloc (asize); mem_to_delete = nullptr; return *this; } /// Add element at end of array. reallocation if necessary. /// Returns index of new element. NETGEN_INLINE index_type Append (const T & el) { if (size == allocsize) ReSize (size+1); data[size] = el; return BASE + size++; } /// Add element at end of array. reallocation not necessary. /// Returns index of new element. NETGEN_INLINE index_type AppendHaveMem (const T & el) { NETGEN_CHECK_RANGE(size, 0, allocsize); data[size] = el; return BASE + size++; } /// Add element at end of array. reallocation if necessary. /// Returns index of new element. NETGEN_INLINE index_type Append (T && el) { if (size == allocsize) ReSize (size+1); data[size] = std::move(el); return BASE + size++; } // Add elements of initializer list to end of array. Reallocation if necessary. NETGEN_INLINE void Append(std::initializer_list lst) { if(allocsize < size + lst.size()) ReSize(size+lst.size()); for(auto val : lst) data[size++] = val; } /// Add element at end of array. reallocation if necessary. NETGEN_INLINE void Insert (size_t pos, const T & el) { if (size == allocsize) ReSize (size+1); for (size_t i = size; i > pos; i--) data[i] = data[i-1]; data[pos] = el; size++; } NETGEN_INLINE Array & operator += (const T & el) { Append (el); return *this; } /// Append array at end of array. reallocation if necessary. NETGEN_INLINE void Append (FlatArray source) { if(size + source.Size() >= allocsize) ReSize (size + source.Size() + 1); for(size_t i = size, j=0; jsize-1; j++) this->data[j] = this->data[j+1]; this->size--; } /// Delete last element. NETGEN_INLINE void DeleteLast () { NETGEN_CHECK_RANGE(size-1,0,size); size--; } /// Deallocate memory NETGEN_INLINE void DeleteAll () { if(mem_to_delete) mt.Free(sizeof(T)*allocsize); delete [] mem_to_delete; mem_to_delete = NULL; data = 0; size = allocsize = 0; } /// Fill array with val NETGEN_INLINE Array & operator= (const T & val) { FlatArray::operator= (val); return *this; } /// array copy NETGEN_INLINE Array & operator= (const Array & a2) { if constexpr (std::is_copy_assignable::value) { SetSize0 (); SetSize (a2.Size()); for (size_t i = 0; i < size; i++) data[i] = a2.data[i]; return *this; } else throw Exception(std::string("cannot copy Array of type ") + typeid(T).name()); } /// steal array NETGEN_INLINE Array & operator= (Array && a2) { mt.Swap(sizeof(T)*allocsize, a2.mt, sizeof(T)*a2.allocsize); ngcore::Swap (size, a2.size); ngcore::Swap (data, a2.data); ngcore::Swap (allocsize, a2.allocsize); ngcore::Swap (mem_to_delete, a2.mem_to_delete); return *this; } /// array copy NETGEN_INLINE Array & operator= (const FlatArray & a2) { SetSize (a2.Size()); for (size_t i = 0; i < size; i++) data[i] = a2[i]; return *this; } /* /// fill array with first, first+1, ... Array & operator= (const IntRange & range) { SetSize (range.Size()); for (int i = 0; i < size; i++) (*this)[i] = range.First()+i; return *this; } */ template Array & operator= (const BaseArrayObject & a2) { size_t newsize = a2.Spec().Size(); SetSize0 (); SetSize (newsize); // for (size_t i = 0; i < newsize; i++) // (*this)[i] = a2.Spec()[i]; size_t i = 0; for (auto val : a2.Spec()) (*this)[i++] = val; return *this; } template Array & operator= (Tuple tup) { SetSize (ArraySize (tup)); StoreToArray (*this, tup); return *this; } Array & operator= (std::initializer_list list) { *this = Array (list); return *this; } // template // Array & operator= (ParallelValue val) // { // FlatArray::operator= (val); // return *this; // } // template // Array & operator= (ParallelFunction val) // { // FlatArray::operator= (val); // return *this; // } NETGEN_INLINE void Swap (Array & b) { mt.Swap(sizeof(T) * allocsize, b.mt, sizeof(T) * b.allocsize); ngcore::Swap (size, b.size); ngcore::Swap (data, b.data); ngcore::Swap (allocsize, b.allocsize); ngcore::Swap (mem_to_delete, b.mem_to_delete); } NETGEN_INLINE void StartMemoryTracing () const { mt.Alloc(sizeof(T) * allocsize); } const MemoryTracer& GetMemoryTracer() const { return mt; } private: /// resize array, at least to size minsize. copy contents NETGEN_INLINE void ReSize (size_t minsize); MemoryTracer mt; }; /// resize array, at least to size minsize. copy contents template NETGEN_INLINE void Array :: ReSize (size_t minsize) { size_t nsize = 2 * allocsize; if (nsize < minsize) nsize = minsize; T * hdata = data; data = new T[nsize]; mt.Alloc(sizeof(T) * nsize); if (hdata) { size_t mins = (nsize < size) ? nsize : size; #if defined(__GNUG__) && __GNUC__ < 5 && !defined(__clang__) for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); #else if (std::is_trivially_copyable::value) memcpy ((void*)data, hdata, sizeof(T)*mins); else for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); #endif if(mem_to_delete) mt.Free(sizeof(T) * allocsize); delete [] mem_to_delete; } mem_to_delete = data; allocsize = nsize; } //extern template class Array; /** Array with static and dynamic memory management. Declares a static array which size is given by the template parameter. If the dynamic size fits into the static size, use static memory, otherwise perform dynamic allocation */ template class ArrayMem : public Array { T mem[S]; using Array::size; using Array::allocsize; using Array::data; using Array::mem_to_delete; // using Array::ownmem; public: /// Generate array of logical and physical size asize explicit ArrayMem(size_t asize = 0) : Array (S, mem) { size = asize; if (asize > S) { data = new T[asize]; allocsize = size; mem_to_delete = data; } } /// copies from Array a2 explicit ArrayMem(const Array & a2) : Array (S, (T*)mem) { Array::operator= (a2); } /// copies from ArrayMem a2 explicit ArrayMem(const ArrayMem & a2) : Array (S, (T*)mem) { Array::operator= (a2); } ArrayMem(ArrayMem && a2) : Array (a2.Size(), (T*)mem) { if (a2.mem_to_delete) { mem_to_delete = a2.mem_to_delete; data = a2.data; allocsize = a2.allocsize; a2.mem_to_delete = nullptr; a2.data = nullptr; a2.size = 0; } else { allocsize = S; for (auto i : ngcore::Range(size)) mem[i] = a2.mem[i]; } } ArrayMem (std::initializer_list list) : ArrayMem (list.size()) { size_t cnt = 0; for (auto val : list) data[cnt++] = val; } template ArrayMem (const BaseArrayObject & a2) : ArrayMem (a2.Size()) { for (size_t i : ngcore::Range(size)) data[i] = a2[i]; } ArrayMem & operator= (const T & val) { FlatArray::operator= (val); return *this; } ArrayMem & operator= (ArrayMem && a2) { ngcore::Swap (mem_to_delete, a2.mem_to_delete); ngcore::Swap (allocsize, a2.allocsize); ngcore::Swap (size, a2.size); if (mem_to_delete==nullptr) { for (auto i : ngcore::Range(size)) mem[i] = std::move(a2.mem[i]); data = mem; } else ngcore::Swap (data, a2.data); return *this; } /// array copy ArrayMem & operator= (const FlatArray & a2) { this->SetSize (a2.Size()); for (size_t i = 0; i < size; i++) (*this)[i] = a2[i]; return *this; } template ArrayMem & operator= (const BaseArrayObject & a2) { this->SetSize (a2.Spec().Size()); size_t i = 0; for (auto val : a2.Spec()) (*this)[i++] = val; return *this; } }; template size_t ArraySize (Tuple /* tup */) { return 0;} template size_t ArraySize (Tuple tup) { return 1+ArraySize(tup.Tail()); } template size_t ArraySize (Tuple tup) { return tup.Head().Size()+ArraySize(tup.Tail()); } template void StoreToArray (FlatArray /* a */, Tuple /* tup */) { ; } template void StoreToArray (FlatArray a, Tuple tup) { a[0] = tup.Head(); StoreToArray (a.Range(1, a.Size()), tup.Tail()); } template void StoreToArray (FlatArray a, Tuple tup) { IntRange r = tup.Head(); a.Range(0,r.Size()) = r; StoreToArray (a.Range(r.Size(), a.Size()), tup.Tail()); } /* template template NETGEN_INLINE Array & Array :: operator= (Tuple tup) { SetSize (ArraySize (tup)); StoreToArray (*this, tup); } */ /* /// append integers to array inline Array & operator+= (Array & array, const IntRange & range) { int oldsize = array.Size(); int s = range.Next() - range.First(); array.SetSize (oldsize+s); for (int i = 0; i < s; i++) array[oldsize+i] = range.First()+i; return array; } */ /* template inline Array & operator+= (Array & array, const BaseArrayObject & a2) { size_t oldsize = array.Size(); size_t s = a2.Spec().Size(); array.SetSize (oldsize+s); for (size_t i = 0; i < s; i++) array[oldsize+i] = a2.Spec()[i]; return array; } */ template inline Array & operator+= (Array & array, const BaseArrayObject & a2) { auto oldsize = array.Size(); auto s = a2.Spec().Size(); array.SetSize (oldsize+s); for (auto val : a2.Spec()) array[oldsize++] = val; return array; } template inline Array operator+= (Array && array, const BaseArrayObject & a2) { array += a2; return std::move(array); } /// bubble sort array template inline void BubbleSort (FlatArray data) { T hv; for (size_t i = 0; i < data.Size(); i++) for (size_t j = i+1; j < data.Size(); j++) if (data[i] > data[j]) { hv = data[i]; data[i] = data[j]; data[j] = hv; } } /// bubble sort array template inline void BubbleSort (FlatArray data, FlatArray index) { for (size_t i = 0; i < data.Size(); i++) for (size_t 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 QuickSort (FlatArray data, TLESS less) { if (data.Size() <= 1) return; ptrdiff_t i = 0; ptrdiff_t j = data.Size()-1; T midval = data[ (i+j)/2 ]; do { while (less (data[i], midval)) i++; while (less (midval, data[j])) j--; if (i <= j) { Swap (data[i], data[j]); i++; j--; } } while (i <= j); QuickSort (data.Range (0, j+1), less); QuickSort (data.Range (i, data.Size()), less); } template NETGEN_INLINE bool DefaultLess (const T & a, const T & b) { return a < b; } template class DefaultLessCl { public: bool operator() (const T & a, const T & b) const { return a < b; } }; template NETGEN_INLINE void QuickSort (FlatArray data) { QuickSort (data, DefaultLessCl()); } template void QuickSortI (FlatArray data, FlatArray index, TLESS less) { if (index.Size() <= 1) return; ptrdiff_t i = 0; ptrdiff_t j = index.Size()-1; int midval = index[ (i+j)/2 ]; do { while (less (data[index[i]],data[midval]) ) i++; while (less (data[midval], data[index[j]])) j--; if (i <= j) { Swap (index[i], index[j]); i++; j--; } } while (i <= j); QuickSortI (data, index.Range (0, j+1), less); QuickSortI (data, index.Range (i, index.Size()), less); } template NETGEN_INLINE void QuickSortI (FlatArray data, FlatArray index) { QuickSortI (data, index, DefaultLessCl()); } template NETGEN_INLINE T xxxRemoveRef (const T & x) { return x; } template class SumArray : public BaseArrayObject> { const TA1 & a1; const TA2 & a2; public: SumArray (const TA1 & aa1, const TA2 & aa2) : a1(aa1), a2(aa2) { ; } size_t Size() const { return a1.Size()+a2.Size(); } auto operator[] (size_t i) const -> decltype (xxxRemoveRef (a1[0])) { return (i < a1.Size()) ? a1[i] : a2[i-a1.Size()]; } }; template SumArray operator+ (const BaseArrayObject & a1, const BaseArrayObject & a2) { return SumArray (a1.Spec(), a2.Spec()); } // head-tail array template class HTArray { HTArray tail; T head; public: HTArray () = default; HTArray (const HTArray &) = default; template HTArray (const HTArray & a2) : tail(a2.Tail()), head(a2.Head()) { ; } HTArray & operator= (const HTArray &) = default; T * Ptr () { return tail.Ptr(); } T & operator[] (size_t i) { return Ptr()[i]; } const T * Ptr () const { return tail.Ptr(); } const T & operator[] (size_t i) const { return Ptr()[i]; } template T & Elem() { return (NR==S-1) ? head : tail.template Elem(); } auto Tail() const { return tail; } auto Head() const { return head; } }; template class HTArray<1,T> { T head; public: HTArray () = default; HTArray (const HTArray &) = default; template HTArray (const HTArray<1,T2> & a2) : head(a2.Head()) { ; } HTArray & operator= (const HTArray &) = default; T * Ptr () { return &head; } T & operator[] (size_t i) { return Ptr()[i]; } const T * Ptr () const { return &head; } const T & operator[] (size_t i) const { return Ptr()[i]; } template T & Elem() { // assert(NR==0, "HTArray index error"); return head; } auto Head() const { return head; } }; template class HTArray<0,T> { // T head; // dummy variable public: HTArray () = default; HTArray (const HTArray &) = default; template HTArray (const HTArray<0,T2> & a2) { ; } HTArray & operator= (const HTArray &) = default; /* T * Ptr () { return &head; } T & operator[] (size_t i) { return Ptr()[i]; } const T * Ptr () const { return &head; } const T & operator[] (size_t i) const { return Ptr()[i]; } template T & Elem() { // assert(false, "HTArray index error"); return head; } */ // T * Ptr () { return (T*)(void*)&head; } T * Ptr () { return (T*)(void*)this; } T & operator[] (size_t i) { return Ptr()[i]; } // const T * Ptr () const { return (const T*)(const void*)&head; } const T * Ptr () const { return (const T*)(const void*)this; } const T & operator[] (size_t i) const { return Ptr()[i]; } template T & Elem() { throw Exception("illegal HTArray<0>::Elem<0>"); } }; template const T * operator+ (const HTArray & ar, size_t i) { return ar.Ptr()+i; } template T * operator+ (HTArray & ar, size_t i) { return ar.Ptr()+i; } template class IteratorPair { TIA a; TIB b; public: IteratorPair (TIA _a, TIB _b) : a(_a), b(_b) { ; } IteratorPair & operator++() { ++a; ++b; return *this; } bool operator!= (const IteratorPair & it2) { return a != it2.a; } auto operator*() { // return pair(*a,*b); return std::pair (*a, *b); // keep reference } }; template class Zip { const TA & a; const TB & b; public: Zip(const TA & _a, const TB & _b) : a(_a), b(_b) { ; } auto begin() const { return IteratorPair(a.begin(), b.begin()); } auto end() const { return IteratorPair(a.end(), b.end()); } }; template inline size_t size (const BaseArrayObject & ao) { return ao.Size(); } template class Enumerate { IntRange r; const TA & a; public: Enumerate(const TA & _a) : r(size(_a)), a(_a) { ; } auto begin() const { return IteratorPair(r.begin(), a.begin()); } auto end() const { return IteratorPair(r.end(), a.end()); } }; } #endif // NETGEN_CORE_ARRAY_HPP