2019-07-09 15:12:41 +05:00
|
|
|
#ifndef NETGEN_CORE_ARRAY_HPP
|
|
|
|
#define NETGEN_CORE_ARRAY_HPP
|
|
|
|
|
|
|
|
/**************************************************************************/
|
|
|
|
/* File: array.hpp */
|
|
|
|
/* Author: Joachim Schoeberl */
|
|
|
|
/* Date: 01. Jun. 95 */
|
|
|
|
/**************************************************************************/
|
|
|
|
|
|
|
|
|
2019-07-09 21:07:19 +05:00
|
|
|
#include "archive.hpp"
|
2019-07-30 16:38:42 +05:00
|
|
|
#include "exception.hpp"
|
2019-07-09 21:07:19 +05:00
|
|
|
#include "localheap.hpp"
|
2019-07-09 15:12:41 +05:00
|
|
|
#include "utils.hpp"
|
|
|
|
|
|
|
|
namespace ngcore
|
|
|
|
{
|
|
|
|
using std::ostream;
|
|
|
|
|
|
|
|
template <typename ... ARGS> class Tuple
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int Size() const { return 0; }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename HEAD, typename ... TAIL>
|
|
|
|
class Tuple<HEAD, TAIL...> : Tuple<TAIL...>
|
|
|
|
{
|
|
|
|
typedef Tuple<TAIL...> BASE;
|
|
|
|
HEAD head;
|
|
|
|
public:
|
|
|
|
Tuple () { ; }
|
|
|
|
Tuple (HEAD h, TAIL ... t) : Tuple<TAIL...> (t...), head(h) { ; }
|
|
|
|
|
|
|
|
HEAD Head() const { return head; }
|
|
|
|
Tuple<TAIL...> Tail() const { return *this; }
|
|
|
|
|
|
|
|
int Size() const { return BASE::Size()+1; }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename ... ARGS>
|
|
|
|
ostream & operator<< (ostream & ost, Tuple<ARGS...> tup)
|
|
|
|
{
|
|
|
|
return ost;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename FIRST, typename ... ARGS>
|
|
|
|
ostream & operator<< (ostream & ost, Tuple<FIRST, ARGS...> tup)
|
|
|
|
{
|
|
|
|
ost << tup.Head() << ", " << tup.Tail();
|
|
|
|
return ost;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename ... ARGS>
|
|
|
|
Tuple<ARGS...> MakeTuple (ARGS ... args)
|
|
|
|
{
|
|
|
|
return Tuple<ARGS...> (args...);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-08-10 03:21:37 +05:00
|
|
|
template <typename AO>
|
|
|
|
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++ ()
|
|
|
|
{ return AOWrapperIterator(ao, ++ind); }
|
|
|
|
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; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-07-09 15:12:41 +05:00
|
|
|
/*
|
|
|
|
Some class which can be treated as array
|
|
|
|
*/
|
|
|
|
template <typename T> // , typename TA = T>
|
|
|
|
class BaseArrayObject
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NETGEN_INLINE BaseArrayObject() { ; }
|
|
|
|
|
|
|
|
NETGEN_INLINE const T & Spec() const { return static_cast<const T&> (*this); }
|
|
|
|
NETGEN_INLINE size_t Size() const { return Spec().Size(); }
|
|
|
|
template <typename T2>
|
|
|
|
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 <typename T2>
|
|
|
|
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 <typename T2>
|
|
|
|
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]; }
|
2019-08-10 03:21:37 +05:00
|
|
|
// NETGEN_INLINE auto begin() const { return Spec().begin(); }
|
|
|
|
// NETGEN_INLINE auto end() const { return Spec().end(); }
|
|
|
|
NETGEN_INLINE auto begin () const { return AOWrapperIterator<BaseArrayObject> (*this, 0); }
|
|
|
|
NETGEN_INLINE auto end () const { return AOWrapperIterator<BaseArrayObject> (*this, Size()); }
|
2019-07-09 15:12:41 +05:00
|
|
|
};
|
2019-08-10 03:21:37 +05:00
|
|
|
|
2019-07-09 15:12:41 +05:00
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class AOWrapper : public BaseArrayObject<AOWrapper<T>>
|
|
|
|
{
|
|
|
|
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<AOWrapper> begin () const { return AOWrapperIterator<AOWrapper> (*this, 0); }
|
|
|
|
NETGEN_INLINE AOWrapperIterator<AOWrapper> end () const { return AOWrapperIterator<AOWrapper> (*this, Size()); }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
NETGEN_INLINE AOWrapper<const T&> ArrayObject (const T & ar)
|
|
|
|
{
|
|
|
|
return AOWrapper<const T&> (ar);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
NETGEN_INLINE AOWrapper<T> ArrayObject (T && ar)
|
|
|
|
{
|
|
|
|
return AOWrapper<T> (ar);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename FUNC>
|
|
|
|
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 <typename T, typename FUNC>
|
|
|
|
auto Substitute (const BaseArrayObject<T> & 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 T>
|
|
|
|
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; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-08-09 18:30:58 +05:00
|
|
|
template <typename T>
|
2019-08-20 21:16:03 +05:00
|
|
|
constexpr T IndexBASE () { return T(0); }
|
2019-07-09 15:12:41 +05:00
|
|
|
|
2019-08-09 18:30:58 +05:00
|
|
|
|
|
|
|
template <class T, class IndexType = size_t> class FlatArray;
|
|
|
|
|
|
|
|
|
|
|
|
template <typename TELEM, typename IndexType>
|
2019-07-09 15:12:41 +05:00
|
|
|
class ArrayIterator
|
|
|
|
{
|
2019-08-09 18:30:58 +05:00
|
|
|
FlatArray<TELEM, IndexType> ar;
|
|
|
|
IndexType ind;
|
2019-07-09 15:12:41 +05:00
|
|
|
public:
|
2019-08-09 18:30:58 +05:00
|
|
|
NETGEN_INLINE ArrayIterator (FlatArray<TELEM, IndexType> aar, IndexType ai)
|
2019-07-09 15:12:41 +05:00
|
|
|
: ar(aar), ind(ai) { ; }
|
|
|
|
NETGEN_INLINE ArrayIterator operator++ (int)
|
|
|
|
{ return ArrayIterator(ar, ind++); }
|
|
|
|
NETGEN_INLINE ArrayIterator operator++ ()
|
|
|
|
{ return ArrayIterator(ar, ++ind); }
|
2019-08-18 15:20:43 +05:00
|
|
|
// 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]; }
|
2019-07-09 15:12:41 +05:00
|
|
|
NETGEN_INLINE bool operator != (ArrayIterator d2) { return ind != d2.ind; }
|
|
|
|
NETGEN_INLINE bool operator == (ArrayIterator d2) { return ind == d2.ind; }
|
|
|
|
};
|
2019-08-18 16:10:58 +05:00
|
|
|
|
2019-07-09 15:12:41 +05:00
|
|
|
|
|
|
|
|
|
|
|
template <typename TSIZE>
|
|
|
|
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 <typename T>
|
|
|
|
class T_Range : public BaseArrayObject <T_Range<T>>
|
|
|
|
{
|
|
|
|
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 <typename T2>
|
|
|
|
NETGEN_INLINE T_Range(T_Range<T2> 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[] (T i) const { return first+i; }
|
|
|
|
NETGEN_INLINE bool Contains (T i) const { return ((i >= first) && (i < next)); }
|
2019-08-10 03:21:37 +05:00
|
|
|
NETGEN_INLINE T_Range Modify(int inc_beg, int inc_end) const
|
|
|
|
{ return T_Range(first+inc_beg, next+inc_end); }
|
2019-07-09 15:12:41 +05:00
|
|
|
NETGEN_INLINE ArrayRangeIterator<T> begin() const { return first; }
|
|
|
|
NETGEN_INLINE ArrayRangeIterator<T> 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<size_t>;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
NETGEN_INLINE T_Range<T> Range (T a, T b)
|
|
|
|
{
|
|
|
|
return T_Range<T>(a,b);
|
|
|
|
}
|
|
|
|
|
2019-08-20 21:16:03 +05:00
|
|
|
template<typename T>
|
|
|
|
NETGEN_INLINE auto Range (const T& ao)
|
|
|
|
-> typename std::enable_if<has_range<T>, decltype(std::declval<T>().Range())>::type
|
|
|
|
{ return ao.Range(); }
|
|
|
|
|
2019-07-09 15:12:41 +05:00
|
|
|
template <typename T>
|
|
|
|
NETGEN_INLINE T_Range<T> Range_impl (T n, std::true_type)
|
|
|
|
{
|
|
|
|
return T_Range<T> (0, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
NETGEN_INLINE auto Range_impl (const T & ao, std::false_type)
|
2019-08-20 21:16:03 +05:00
|
|
|
-> T_Range<index_type<T>>
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
2019-08-20 21:16:03 +05:00
|
|
|
return T_Range<index_type<T>> (IndexBASE<index_type<T>>(),
|
|
|
|
IndexBASE<index_type<T>>() + index_type<T>(ao.Size()));
|
2019-07-09 15:12:41 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2019-08-20 21:16:03 +05:00
|
|
|
auto Range(const T & x)
|
2019-08-21 12:44:31 +05:00
|
|
|
-> typename std::enable_if<std::is_integral_v<T> || !has_range<T>,
|
|
|
|
decltype(Range_impl(x, std::is_integral<T>()))>::type {
|
2019-07-09 15:12:41 +05:00
|
|
|
return Range_impl(x, std::is_integral<T>());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 <typename TI>
|
|
|
|
inline ostream & operator<< (ostream & s, T_Range<TI> ir)
|
|
|
|
{
|
|
|
|
s << "[" << ir.First() << "," << ir.Next() << ")";
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename ... ARGS>
|
|
|
|
ostream & operator<< (ostream & ost, Tuple<IntRange, ARGS...> tup)
|
|
|
|
{
|
|
|
|
ost << tup.Head() << ", " << tup.Tail();
|
|
|
|
return ost;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
inline ostream & operator<< (ostream & ost, const BaseArrayObject<T> & array)
|
|
|
|
{
|
|
|
|
for (auto i : Range(array.Size()))
|
|
|
|
ost << i << ":" << array[i] << std::endl;
|
|
|
|
return ost;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-08-18 16:10:58 +05:00
|
|
|
template <typename T, typename TI, typename INDEX_ARRAY>
|
|
|
|
class IndirectArray : public BaseArrayObject<IndirectArray<T, TI, INDEX_ARRAY> >
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
2019-08-18 16:10:58 +05:00
|
|
|
FlatArray<T,TI> ba;
|
2019-07-09 15:12:41 +05:00
|
|
|
const INDEX_ARRAY & ia;
|
|
|
|
|
|
|
|
public:
|
2019-08-18 16:10:58 +05:00
|
|
|
NETGEN_INLINE IndirectArray (FlatArray<T,TI> aba,
|
2019-07-09 15:12:41 +05:00
|
|
|
const INDEX_ARRAY & aia)
|
|
|
|
: ba(aba), ia(aia) { ; }
|
|
|
|
|
|
|
|
NETGEN_INLINE size_t Size() const { return ia.Size(); }
|
2019-08-18 15:20:43 +05:00
|
|
|
NETGEN_INLINE T & operator[] (size_t i) const { return ba[ia[i]]; }
|
|
|
|
// NETGEN_INLINE T & operator[] (size_t i) { return ba[ia[i]]; }
|
2019-07-09 15:12:41 +05:00
|
|
|
|
|
|
|
NETGEN_INLINE IndirectArray operator= (const T & val)
|
|
|
|
{
|
|
|
|
for (auto i : Range(Size()))
|
|
|
|
(*this)[i] = val;
|
|
|
|
return IndirectArray (ba, ia);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T2>
|
|
|
|
NETGEN_INLINE IndirectArray operator= (const BaseArrayObject<T2> & a2)
|
|
|
|
{
|
|
|
|
for (auto i : Range(Size()))
|
|
|
|
(*this)[i] = a2[i];
|
|
|
|
return IndirectArray (ba, ia);
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:20:43 +05:00
|
|
|
NETGEN_INLINE AOWrapperIterator<IndirectArray> begin() const { return { *this, 0 }; }
|
|
|
|
NETGEN_INLINE AOWrapperIterator<IndirectArray> end() const { return { *this, Size() }; }
|
2019-07-09 15:12:41 +05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
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.
|
2019-07-30 16:38:42 +05:00
|
|
|
Optional range check by macro NETGEN_CHECK_RANGE
|
2019-07-09 15:12:41 +05:00
|
|
|
*/
|
2019-08-09 18:30:58 +05:00
|
|
|
template <class T, class IndexType>
|
|
|
|
class FlatArray : public BaseArrayObject<FlatArray<T,IndexType> >
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
|
|
|
protected:
|
2019-08-20 21:16:03 +05:00
|
|
|
static constexpr IndexType BASE = IndexBASE<IndexType>();
|
2019-07-09 15:12:41 +05:00
|
|
|
/// the size
|
|
|
|
size_t size;
|
|
|
|
/// the data
|
|
|
|
T * __restrict data;
|
|
|
|
public:
|
2019-08-12 17:19:16 +05:00
|
|
|
typedef T value_type;
|
|
|
|
typedef IndexType index_type;
|
2019-08-09 18:30:58 +05:00
|
|
|
using BaseArrayObject<FlatArray>::ILLEGAL_POSITION;
|
2019-07-09 15:12:41 +05:00
|
|
|
|
|
|
|
/// initialize array
|
|
|
|
NETGEN_INLINE FlatArray () = default;
|
|
|
|
// { ; } // size = 0; data = 0; }
|
|
|
|
|
|
|
|
/// copy constructor allows size-type conversion
|
2019-08-09 18:30:58 +05:00
|
|
|
NETGEN_INLINE FlatArray (const FlatArray & a2) = default;
|
2019-07-09 15:12:41 +05:00
|
|
|
// : size(a2.Size()), data(a2.data) { ; }
|
|
|
|
|
|
|
|
/// provide size and memory
|
|
|
|
NETGEN_INLINE FlatArray (size_t asize, T * adata)
|
|
|
|
: size(asize), data(adata) { ; }
|
|
|
|
|
2019-07-09 21:07:19 +05:00
|
|
|
/// 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<T> (asize))
|
|
|
|
{ ; }
|
2019-07-09 15:12:41 +05:00
|
|
|
|
|
|
|
/// the size
|
|
|
|
NETGEN_INLINE size_t Size() const { return size; }
|
|
|
|
|
|
|
|
/// 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;
|
2019-08-10 03:21:37 +05:00
|
|
|
for (size_t i = 0; i < hsize; i++) hdata[i] = a2.data[i];
|
2019-07-09 15:12:41 +05:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T2>
|
|
|
|
NETGEN_INLINE const FlatArray & operator= (const BaseArrayObject<T2> & a2) const
|
|
|
|
{
|
|
|
|
size_t hsize = size;
|
|
|
|
T * hdata = data;
|
2019-08-10 03:21:37 +05:00
|
|
|
auto p2 = a2.begin();
|
|
|
|
for (size_t i = 0; i < hsize; i++, p2++) hdata[i] = *p2;
|
2019-07-09 15:12:41 +05:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
NETGEN_INLINE const FlatArray & operator= (const std::function<T(int)> & func) const
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < size; i++)
|
2019-08-10 03:21:37 +05:00
|
|
|
data[i] = func(i+BASE);
|
2019-07-09 15:12:41 +05:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// template <typename T2>
|
|
|
|
// const FlatArray operator= (ParallelValue<T2> val);
|
|
|
|
// template <typename T2>
|
|
|
|
// const FlatArray operator= (ParallelFunction<T2> val);
|
|
|
|
|
|
|
|
/// copies pointers
|
|
|
|
NETGEN_INLINE const FlatArray & Assign (const FlatArray & a2)
|
|
|
|
{
|
|
|
|
size = a2.size;
|
|
|
|
data = a2.data;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2019-07-09 21:07:19 +05:00
|
|
|
/// assigns memory from local heap
|
|
|
|
NETGEN_INLINE const FlatArray & Assign (size_t asize, LocalHeap & lh)
|
|
|
|
{
|
|
|
|
size = asize;
|
|
|
|
data = lh.Alloc<T> (asize);
|
|
|
|
return *this;
|
|
|
|
}
|
2019-07-09 15:12:41 +05:00
|
|
|
|
2019-07-30 16:38:42 +05:00
|
|
|
/// Access array. range check by macro NETGEN_CHECK_RANGE
|
2019-08-09 18:30:58 +05:00
|
|
|
NETGEN_INLINE T & operator[] (IndexType i) const
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
2019-08-10 03:21:37 +05:00
|
|
|
NETGEN_CHECK_RANGE(i,BASE,size+BASE);
|
2019-08-09 18:30:58 +05:00
|
|
|
return data[i-BASE];
|
2019-07-09 15:12:41 +05:00
|
|
|
}
|
|
|
|
|
2019-08-20 21:16:03 +05:00
|
|
|
NETGEN_INLINE T_Range<index_type> Range () const
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
2019-08-20 21:16:03 +05:00
|
|
|
return T_Range<index_type> (BASE, size+BASE);
|
2019-07-09 15:12:41 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
NETGEN_INLINE const CArray<T> Addr (size_t pos) const
|
|
|
|
{
|
2019-08-10 03:21:37 +05:00
|
|
|
return CArray<T> (data+pos-BASE);
|
2019-07-09 15:12:41 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
// const CArray<T> operator+ (int pos)
|
|
|
|
// { return CArray<T> (data+pos); }
|
|
|
|
NETGEN_INLINE T * operator+ (size_t pos) const { return data+pos; }
|
|
|
|
|
2019-07-30 16:38:42 +05:00
|
|
|
/// access last element. check by macro NETGEN_CHECK_RANGE
|
2019-07-09 15:12:41 +05:00
|
|
|
T & Last () const
|
|
|
|
{
|
2019-08-05 15:48:08 +05:00
|
|
|
NETGEN_CHECK_RANGE(size-1,0,size);
|
2019-07-09 15:12:41 +05:00
|
|
|
return data[size-1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/// takes sub-array starting from position pos
|
|
|
|
NETGEN_INLINE const FlatArray<T> Part (size_t pos)
|
|
|
|
{
|
|
|
|
return FlatArray<T> (size-pos, data+pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// takes subsize elements starting from position pos
|
|
|
|
NETGEN_INLINE const FlatArray<T> Part (size_t pos, size_t subsize)
|
|
|
|
{
|
|
|
|
return FlatArray<T> (subsize, data+pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// takes range starting from position start of end-start elements
|
|
|
|
NETGEN_INLINE FlatArray<T> Range (size_t start, size_t end) const
|
|
|
|
{
|
|
|
|
return FlatArray<T> (end-start, data+start);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// takes range starting from position start of end-start elements
|
|
|
|
NETGEN_INLINE FlatArray<T> Range (T_Range<size_t> range) const
|
|
|
|
{
|
|
|
|
return FlatArray<T> (range.Size(), data+range.First());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// takes range starting from position start of end-start elements
|
2019-08-12 17:19:16 +05:00
|
|
|
NETGEN_INLINE const FlatArray<T> operator[] (T_Range<IndexType> range) const
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
|
|
|
return FlatArray<T> (range.Size(), data+range.First());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename TI1>
|
2019-08-18 16:10:58 +05:00
|
|
|
auto operator[] (const BaseArrayObject<TI1> & ind_array) const
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
2019-08-18 16:10:58 +05:00
|
|
|
return IndirectArray<T, IndexType, BaseArrayObject<TI1> > (*this, ind_array);
|
2019-07-09 15:12:41 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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;
|
|
|
|
}
|
|
|
|
|
2019-08-09 18:30:58 +05:00
|
|
|
auto begin() const { return ArrayIterator<T,IndexType> (*this, BASE); }
|
|
|
|
auto end() const { return ArrayIterator<T,IndexType> (*this, size+BASE); }
|
2019-07-09 15:12:41 +05:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
FlatArray<T> View (FlatArray<T> fa) { return fa; }
|
|
|
|
|
|
|
|
/// print array
|
|
|
|
template <class T>
|
|
|
|
inline ostream & operator<< (ostream & s, const FlatArray<T> & a)
|
|
|
|
{
|
|
|
|
for (auto i : a.Range())
|
|
|
|
s << i << ": " << a[i] << "\n";
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// have arrays the same contents ?
|
|
|
|
template <class T1, class T2>
|
|
|
|
inline bool operator== (const FlatArray<T1> & a1,
|
|
|
|
const FlatArray<T2> & 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Dynamic array container.
|
|
|
|
|
|
|
|
Array<T> 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.
|
|
|
|
*/
|
2019-08-09 18:30:58 +05:00
|
|
|
template <class T, class IndexType = size_t>
|
|
|
|
class Array : public FlatArray<T, IndexType>
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2019-08-09 18:30:58 +05:00
|
|
|
using FlatArray<T,IndexType>::size;
|
|
|
|
using FlatArray<T,IndexType>::data;
|
2019-08-10 03:21:37 +05:00
|
|
|
using FlatArray<T,IndexType>::BASE;
|
2019-07-09 15:12:41 +05:00
|
|
|
|
|
|
|
public:
|
|
|
|
/// Generate array of logical and physical size asize
|
|
|
|
NETGEN_INLINE explicit Array()
|
2019-08-09 18:30:58 +05:00
|
|
|
: FlatArray<T,IndexType> (0, nullptr)
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
|
|
|
allocsize = 0;
|
|
|
|
mem_to_delete = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
NETGEN_INLINE explicit Array(size_t asize)
|
2019-08-09 18:30:58 +05:00
|
|
|
: FlatArray<T,IndexType> (asize, new T[asize])
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
|
|
|
allocsize = asize;
|
|
|
|
mem_to_delete = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Generate array in user data
|
|
|
|
NETGEN_INLINE Array(size_t asize, T* adata, bool ownMemory = false)
|
|
|
|
: FlatArray<T> (asize, adata)
|
|
|
|
{
|
|
|
|
allocsize = asize;
|
|
|
|
if(ownMemory)
|
|
|
|
mem_to_delete = adata;
|
|
|
|
else
|
|
|
|
mem_to_delete = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate array in user data
|
|
|
|
template <typename ALLOCATOR>
|
|
|
|
NETGEN_INLINE Array(size_t asize, ALLOCATOR & lh)
|
|
|
|
: FlatArray<T> (asize, lh)
|
|
|
|
{
|
|
|
|
allocsize = asize;
|
|
|
|
mem_to_delete = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
NETGEN_INLINE Array (Array && a2)
|
|
|
|
{
|
|
|
|
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)
|
2019-08-09 18:30:58 +05:00
|
|
|
: FlatArray<T,IndexType> (a2.Size(), a2.Size() ? new T[a2.Size()] : nullptr)
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
|
|
|
allocsize = size;
|
|
|
|
mem_to_delete = data;
|
|
|
|
for (size_t i = 0; i < size; i++)
|
2019-08-09 18:30:58 +05:00
|
|
|
data[i] = a2.data[i];
|
2019-07-09 15:12:41 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename TA>
|
|
|
|
explicit Array (const BaseArrayObject<TA> & a2)
|
2019-08-09 18:30:58 +05:00
|
|
|
: FlatArray<T,IndexType> (a2.Size(),
|
|
|
|
a2.Size() ? new T[a2.Size()] : nullptr)
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
|
|
|
allocsize = size;
|
|
|
|
mem_to_delete = data;
|
2019-08-10 03:21:37 +05:00
|
|
|
/*
|
2019-07-09 15:12:41 +05:00
|
|
|
for (size_t i = 0; i < size; i++)
|
|
|
|
data[i] = a2[i];
|
2019-08-10 03:21:37 +05:00
|
|
|
*/
|
|
|
|
auto p2 = a2.begin();
|
|
|
|
for (size_t i = 0; i < size; i++, p2++)
|
|
|
|
data[i] = *p2;
|
|
|
|
|
2019-07-09 15:12:41 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
Array (std::initializer_list<T> list)
|
|
|
|
: FlatArray<T> (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<T> & a2, const Array<T> & a3)
|
|
|
|
: FlatArray<T> (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++)
|
2019-08-10 03:21:37 +05:00
|
|
|
data[i] = a2[i];
|
2019-07-09 15:12:41 +05:00
|
|
|
for (size_t i = a2.Size(), j=0; i < size; i++,j++)
|
2019-08-10 03:21:37 +05:00
|
|
|
data[i] = a3[j];
|
2019-07-09 15:12:41 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// if responsible, deletes memory
|
|
|
|
NETGEN_INLINE ~Array()
|
|
|
|
{
|
|
|
|
delete [] mem_to_delete;
|
|
|
|
}
|
|
|
|
|
2019-07-09 21:07:19 +05:00
|
|
|
// Only provide this function if T is archivable
|
|
|
|
template<typename T2=T>
|
|
|
|
auto DoArchive(Archive& archive) -> typename std::enable_if_t<is_archivable<T2>, void>
|
|
|
|
{
|
|
|
|
if(archive.Output())
|
|
|
|
archive << size;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t s;
|
|
|
|
archive & s;
|
|
|
|
SetSize(s);
|
|
|
|
}
|
|
|
|
archive.Do(data, size);
|
|
|
|
}
|
2019-07-09 15:12:41 +05:00
|
|
|
|
|
|
|
/// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-09 21:07:19 +05:00
|
|
|
/// assigns memory from local heap
|
|
|
|
NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh)
|
|
|
|
{
|
|
|
|
delete [] mem_to_delete;
|
|
|
|
size = allocsize = asize;
|
|
|
|
data = lh.Alloc<T> (asize);
|
|
|
|
mem_to_delete = nullptr;
|
|
|
|
return *this;
|
|
|
|
}
|
2019-07-09 15:12:41 +05:00
|
|
|
|
|
|
|
/// Add element at end of array. reallocation if necessary.
|
|
|
|
NETGEN_INLINE size_t Append (const T & el)
|
|
|
|
{
|
|
|
|
if (size == allocsize)
|
|
|
|
ReSize (size+1);
|
|
|
|
data[size] = el;
|
|
|
|
size++;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add element at end of array. reallocation not necessary.
|
|
|
|
NETGEN_INLINE size_t AppendHaveMem (const T & el)
|
|
|
|
{
|
|
|
|
data[size] = el;
|
|
|
|
size++;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Add element at end of array. reallocation if necessary.
|
|
|
|
NETGEN_INLINE size_t Append (T && el)
|
|
|
|
{
|
|
|
|
if (size == allocsize)
|
|
|
|
ReSize (size+1);
|
2019-07-09 21:07:19 +05:00
|
|
|
data[size] = std::move(el);
|
2019-07-09 15:12:41 +05:00
|
|
|
size++;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add elements of initializer list to end of array. Reallocation if necessary.
|
|
|
|
NETGEN_INLINE size_t Append(std::initializer_list<T> lst)
|
|
|
|
{
|
|
|
|
if(allocsize < size + lst.size())
|
|
|
|
ReSize(size+lst.size());
|
|
|
|
for(auto val : lst)
|
|
|
|
data[size++] = val;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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<T> & operator += (const T & el)
|
|
|
|
{
|
|
|
|
Append (el);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Append array at end of array. reallocation if necessary.
|
|
|
|
// int Append (const Array<T> & source)
|
|
|
|
NETGEN_INLINE size_t Append (FlatArray<T> source)
|
|
|
|
{
|
|
|
|
if(size + source.Size() >= allocsize)
|
|
|
|
ReSize (size + source.Size() + 1);
|
|
|
|
|
|
|
|
for(size_t i = size, j=0; j<source.Size(); i++, j++)
|
|
|
|
data[i] = source[j];
|
|
|
|
|
|
|
|
size += source.Size();
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Delete element i. Move last element to position i.
|
|
|
|
NETGEN_INLINE void DeleteElement (size_t i)
|
|
|
|
{
|
2019-08-10 03:21:37 +05:00
|
|
|
NETGEN_CHECK_RANGE(i,BASE,BASE+size);
|
|
|
|
data[i-BASE] = std::move(data[size-1]);
|
2019-07-09 15:12:41 +05:00
|
|
|
size--;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Delete element i. Move all remaining elements forward
|
|
|
|
NETGEN_INLINE void RemoveElement (size_t i)
|
|
|
|
{
|
|
|
|
for(size_t j = i; j < this->size-1; j++)
|
|
|
|
this->data[j] = this->data[j+1];
|
|
|
|
this->size--;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Delete last element.
|
|
|
|
NETGEN_INLINE void DeleteLast ()
|
|
|
|
{
|
2019-08-05 15:48:08 +05:00
|
|
|
NETGEN_CHECK_RANGE(size-1,0,size);
|
2019-07-09 15:12:41 +05:00
|
|
|
size--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Deallocate memory
|
|
|
|
NETGEN_INLINE void DeleteAll ()
|
|
|
|
{
|
|
|
|
delete [] mem_to_delete;
|
|
|
|
mem_to_delete = NULL;
|
|
|
|
data = 0;
|
|
|
|
size = allocsize = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Fill array with val
|
|
|
|
NETGEN_INLINE Array & operator= (const T & val)
|
|
|
|
{
|
2019-08-10 03:21:37 +05:00
|
|
|
FlatArray<T,IndexType>::operator= (val);
|
2019-07-09 15:12:41 +05:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// array copy
|
|
|
|
NETGEN_INLINE Array & operator= (const Array & a2)
|
|
|
|
{
|
|
|
|
SetSize0 ();
|
|
|
|
SetSize (a2.Size());
|
|
|
|
for (size_t i = 0; i < size; i++)
|
2019-08-10 03:21:37 +05:00
|
|
|
data[i] = a2.data[i];
|
2019-07-09 15:12:41 +05:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// steal array
|
|
|
|
NETGEN_INLINE Array & operator= (Array && a2)
|
|
|
|
{
|
|
|
|
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<T> & a2)
|
|
|
|
{
|
|
|
|
SetSize (a2.Size());
|
|
|
|
for (size_t i = 0; i < size; i++)
|
2019-08-10 03:21:37 +05:00
|
|
|
data[i] = a2[i];
|
2019-07-09 15:12:41 +05:00
|
|
|
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 <typename T2>
|
|
|
|
Array & operator= (const BaseArrayObject<T2> & 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 <typename ...ARGS>
|
|
|
|
Array & operator= (Tuple<ARGS...> tup)
|
|
|
|
{
|
|
|
|
SetSize (ArraySize (tup));
|
|
|
|
StoreToArray (*this, tup);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Array & operator= (std::initializer_list<T> list)
|
|
|
|
{
|
|
|
|
*this = Array<T> (list);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// template <typename T2>
|
|
|
|
// Array & operator= (ParallelValue<T2> val)
|
|
|
|
// {
|
|
|
|
// FlatArray<T>::operator= (val);
|
|
|
|
// return *this;
|
|
|
|
// }
|
|
|
|
// template <typename T2>
|
|
|
|
// Array & operator= (ParallelFunction<T2> val)
|
|
|
|
// {
|
|
|
|
// FlatArray<T>::operator= (val);
|
|
|
|
// return *this;
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
NETGEN_INLINE void Swap (Array & b)
|
|
|
|
{
|
|
|
|
ngcore::Swap (size, b.size);
|
|
|
|
ngcore::Swap (data, b.data);
|
|
|
|
ngcore::Swap (allocsize, b.allocsize);
|
|
|
|
ngcore::Swap (mem_to_delete, b.mem_to_delete);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/// resize array, at least to size minsize. copy contents
|
|
|
|
NETGEN_INLINE void ReSize (size_t minsize);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// resize array, at least to size minsize. copy contents
|
2019-08-09 18:30:58 +05:00
|
|
|
template <class T, class IndexType>
|
|
|
|
NETGEN_INLINE void Array<T, IndexType> :: ReSize (size_t minsize)
|
2019-07-09 15:12:41 +05:00
|
|
|
{
|
|
|
|
size_t nsize = 2 * allocsize;
|
|
|
|
if (nsize < minsize) nsize = minsize;
|
|
|
|
|
|
|
|
T * hdata = data;
|
|
|
|
data = new T[nsize];
|
|
|
|
|
|
|
|
if (hdata)
|
|
|
|
{
|
|
|
|
size_t mins = (nsize < size) ? nsize : size;
|
|
|
|
#if defined(__GNUG__) && __GNUC__ < 5 && !defined(__clang__)
|
2019-07-09 21:07:19 +05:00
|
|
|
for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]);
|
2019-07-09 15:12:41 +05:00
|
|
|
#else
|
|
|
|
if (std::is_trivially_copyable<T>::value)
|
|
|
|
memcpy ((void*)data, hdata, sizeof(T)*mins);
|
|
|
|
else
|
2019-07-09 21:07:19 +05:00
|
|
|
for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]);
|
2019-07-09 15:12:41 +05:00
|
|
|
#endif
|
|
|
|
delete [] mem_to_delete;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_to_delete = data;
|
|
|
|
allocsize = nsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
//extern template class Array<int,int>;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
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 T, int S>
|
|
|
|
class ArrayMem : public Array<T>
|
|
|
|
{
|
|
|
|
T mem[S];
|
|
|
|
|
|
|
|
using Array<T>::size;
|
|
|
|
using Array<T>::allocsize;
|
|
|
|
using Array<T>::data;
|
|
|
|
using Array<T>::mem_to_delete;
|
|
|
|
// using Array<T>::ownmem;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/// Generate array of logical and physical size asize
|
|
|
|
explicit ArrayMem(size_t asize = 0)
|
|
|
|
: Array<T> (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<T> & a2)
|
|
|
|
: Array<T> (S, (T*)mem)
|
|
|
|
{
|
|
|
|
Array<T>::operator= (a2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// copies from ArrayMem a2
|
|
|
|
explicit ArrayMem(const ArrayMem & a2)
|
|
|
|
: Array<T> (S, (T*)mem)
|
|
|
|
{
|
|
|
|
Array<T>::operator= (a2);
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayMem(ArrayMem && a2)
|
|
|
|
: Array<T> (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;
|
2019-07-12 12:09:38 +05:00
|
|
|
for (auto i : ngcore::Range(size))
|
2019-07-09 15:12:41 +05:00
|
|
|
mem[i] = a2.mem[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayMem (std::initializer_list<T> list)
|
|
|
|
: ArrayMem (list.size())
|
|
|
|
{
|
|
|
|
size_t cnt = 0;
|
|
|
|
for (auto val : list)
|
|
|
|
data[cnt++] = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ArrayMem & operator= (const T & val)
|
|
|
|
{
|
|
|
|
FlatArray<T>::operator= (val);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2019-07-11 18:21:47 +05:00
|
|
|
ArrayMem & operator= (ArrayMem && a2)
|
|
|
|
{
|
2019-07-11 20:58:23 +05:00
|
|
|
ngcore::Swap (mem_to_delete, a2.mem_to_delete);
|
|
|
|
ngcore::Swap (allocsize, a2.allocsize);
|
|
|
|
ngcore::Swap (size, a2.size);
|
|
|
|
|
|
|
|
if (mem_to_delete==nullptr)
|
2019-07-12 11:52:50 +05:00
|
|
|
{
|
2019-07-12 12:09:38 +05:00
|
|
|
for (auto i : ngcore::Range(size))
|
2019-07-11 20:58:23 +05:00
|
|
|
mem[i] = std::move(a2.mem[i]);
|
2019-07-12 11:52:50 +05:00
|
|
|
data = mem;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ngcore::Swap (data, a2.data);
|
2019-07-11 20:58:23 +05:00
|
|
|
|
2019-07-11 18:21:47 +05:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-09 15:12:41 +05:00
|
|
|
/// array copy
|
|
|
|
ArrayMem & operator= (const FlatArray<T> & a2)
|
|
|
|
{
|
|
|
|
this->SetSize (a2.Size());
|
|
|
|
for (size_t i = 0; i < size; i++)
|
|
|
|
(*this)[i] = a2[i];
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T2>
|
|
|
|
ArrayMem & operator= (const BaseArrayObject<T2> & a2)
|
|
|
|
{
|
|
|
|
this->SetSize (a2.Spec().Size());
|
|
|
|
|
|
|
|
size_t i = 0;
|
|
|
|
for (auto val : a2.Spec())
|
|
|
|
(*this)[i++] = val;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename ... ARGS>
|
|
|
|
size_t ArraySize (Tuple<ARGS...> tup)
|
|
|
|
{ return 0;}
|
|
|
|
|
|
|
|
template <typename ... ARGS>
|
|
|
|
size_t ArraySize (Tuple<int,ARGS...> tup)
|
|
|
|
{ return 1+ArraySize(tup.Tail()); }
|
|
|
|
|
|
|
|
template <typename ... ARGS>
|
|
|
|
size_t ArraySize (Tuple<IntRange,ARGS...> tup)
|
|
|
|
{ return tup.Head().Size()+ArraySize(tup.Tail()); }
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T, typename ... ARGS>
|
|
|
|
void StoreToArray (FlatArray<T> a, Tuple<ARGS...> tup) { ; }
|
|
|
|
|
|
|
|
template <typename T, typename ... ARGS>
|
|
|
|
void StoreToArray (FlatArray<T> a, Tuple<int,ARGS...> tup)
|
|
|
|
{
|
|
|
|
a[0] = tup.Head();
|
|
|
|
StoreToArray (a.Range(1, a.Size()), tup.Tail());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename ... ARGS>
|
|
|
|
void StoreToArray (FlatArray<T> a, Tuple<IntRange,ARGS...> tup)
|
|
|
|
{
|
|
|
|
IntRange r = tup.Head();
|
|
|
|
a.Range(0,r.Size()) = r;
|
|
|
|
StoreToArray (a.Range(r.Size(), a.Size()), tup.Tail());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
template <typename T> template <typename ...ARGS>
|
|
|
|
NETGEN_INLINE Array<T> & Array<T> :: operator= (Tuple<ARGS...> tup)
|
|
|
|
{
|
|
|
|
SetSize (ArraySize (tup));
|
|
|
|
StoreToArray (*this, tup);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
/// append integers to array
|
|
|
|
inline Array<int> & operator+= (Array<int> & 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 <typename T, typename T2>
|
|
|
|
inline Array<T> & operator+= (Array<T> & array, const BaseArrayObject<T2> & 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 <typename T, typename T2>
|
|
|
|
inline Array<T> & operator+= (Array<T> & array, const BaseArrayObject<T2> & a2)
|
|
|
|
{
|
|
|
|
auto oldsize = array.Size();
|
|
|
|
auto s = a2.Spec().Size();
|
|
|
|
|
|
|
|
array.SetSize (oldsize+s);
|
|
|
|
|
|
|
|
for (auto val : a2.Spec())
|
|
|
|
array[oldsize++] = val;
|
|
|
|
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// bubble sort array
|
|
|
|
template <class T>
|
|
|
|
inline void BubbleSort (FlatArray<T> 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 <class T, class S>
|
|
|
|
inline void BubbleSort (FlatArray<T> data, FlatArray<S> slave)
|
|
|
|
{
|
|
|
|
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 = slave[i];
|
|
|
|
slave[i] = slave[j];
|
|
|
|
slave[j] = hvs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class T, typename TLESS>
|
|
|
|
void QuickSort (FlatArray<T> 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 <typename T>
|
|
|
|
NETGEN_INLINE bool DefaultLess (const T & a, const T & b)
|
|
|
|
{
|
|
|
|
return a < b;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class DefaultLessCl
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
bool operator() (const T & a, const T & b) const
|
|
|
|
{
|
|
|
|
return a < b;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
NETGEN_INLINE void QuickSort (FlatArray<T> data)
|
|
|
|
{
|
|
|
|
QuickSort (data, DefaultLessCl<T>());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class T, typename TLESS>
|
|
|
|
void QuickSortI (FlatArray<T> data, FlatArray<int> 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 <class T>
|
|
|
|
NETGEN_INLINE void QuickSortI (FlatArray<T> data, FlatArray<int> index)
|
|
|
|
{
|
|
|
|
QuickSortI (data, index, DefaultLessCl<T>());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
NETGEN_INLINE T xxxRemoveRef (const T & x)
|
|
|
|
{
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class TA1, class TA2>
|
|
|
|
class SumArray : public BaseArrayObject<SumArray<TA1,TA2>>
|
|
|
|
{
|
|
|
|
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 <class TA1, class TA2>
|
|
|
|
SumArray<TA1,TA2> operator+ (const BaseArrayObject<TA1> & a1,
|
|
|
|
const BaseArrayObject<TA2> & a2)
|
|
|
|
{
|
|
|
|
return SumArray<TA1,TA2> (a1.Spec(), a2.Spec());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// head-tail array
|
|
|
|
template <size_t S, typename T>
|
|
|
|
class HTArray
|
|
|
|
{
|
|
|
|
HTArray<S-1,T> tail;
|
|
|
|
T head;
|
|
|
|
public:
|
|
|
|
HTArray () = default;
|
|
|
|
HTArray (const HTArray &) = default;
|
|
|
|
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 <int NR>
|
|
|
|
T & Elem() { return (NR==S-1) ? head : tail.template Elem<NR>(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class HTArray<1,T>
|
|
|
|
{
|
|
|
|
T head;
|
|
|
|
public:
|
|
|
|
HTArray () = default;
|
|
|
|
HTArray (const HTArray &) = default;
|
|
|
|
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 <int NR>
|
|
|
|
T & Elem()
|
|
|
|
{
|
|
|
|
// assert(NR==0, "HTArray index error");
|
|
|
|
return head;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class HTArray<0,T>
|
|
|
|
{
|
|
|
|
// T head; // dummy variable
|
|
|
|
public:
|
|
|
|
HTArray () = default;
|
|
|
|
HTArray (const HTArray &) = default;
|
|
|
|
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 <int NR>
|
|
|
|
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 <int NR>
|
|
|
|
T & Elem()
|
|
|
|
{
|
|
|
|
throw Exception("illegal HTArray<0>::Elem<0>");
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
template<size_t S, typename T>
|
|
|
|
const T * operator+ (const HTArray<S,T> & ar, size_t i)
|
|
|
|
{
|
|
|
|
return ar.Ptr()+i;
|
|
|
|
}
|
|
|
|
template<size_t S, typename T>
|
|
|
|
T * operator+ (HTArray<S,T> & ar, size_t i)
|
|
|
|
{
|
|
|
|
return ar.Ptr()+i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif // NETGEN_CORE_ARRAY_HPP
|
|
|
|
|