1044 lines
27 KiB
C++
1044 lines
27 KiB
C++
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
#ifndef MFEM_ARRAY
|
|
#define MFEM_ARRAY
|
|
|
|
#include "../config/config.hpp"
|
|
#include "mem_manager.hpp"
|
|
#include "device.hpp"
|
|
#include "error.hpp"
|
|
#include "globals.hpp"
|
|
|
|
#include <iostream>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <algorithm>
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
template <class T>
|
|
class Array;
|
|
|
|
template <class T>
|
|
void Swap(Array<T> &, Array<T> &);
|
|
|
|
/**
|
|
Abstract data type Array.
|
|
|
|
Array<T> is an automatically increasing array containing elements of the
|
|
generic type T. The allocated size may be larger then the logical size
|
|
of the array.
|
|
The elements can be accessed by the [] operator, the range is 0 to size-1.
|
|
*/
|
|
template <class T>
|
|
class Array
|
|
{
|
|
protected:
|
|
/// Pointer to data
|
|
Memory<T> data;
|
|
/// Size of the array
|
|
int size;
|
|
|
|
inline void GrowSize(int minsize);
|
|
|
|
public:
|
|
friend void Swap<T>(Array<T> &, Array<T> &);
|
|
|
|
/// Creates an empty array
|
|
inline Array() : size(0) { data.Reset(); }
|
|
|
|
/// Creates an empty array with a given MemoryType
|
|
inline Array(MemoryType mt) : size(0) { data.Reset(mt); }
|
|
|
|
/// Creates array of @a asize elements
|
|
explicit inline Array(int asize)
|
|
: size(asize) { asize > 0 ? data.New(asize) : data.Reset(); }
|
|
|
|
/** @brief Creates array using an existing c-array of asize elements;
|
|
allocsize is set to -asize to indicate that the data will not
|
|
be deleted. */
|
|
inline Array(T *_data, int asize)
|
|
{ data.Wrap(_data, asize, false); size = asize; }
|
|
|
|
/// Copy constructor: deep copy from @a src
|
|
/** This method supports source arrays using any MemoryType. */
|
|
inline Array(const Array &src);
|
|
|
|
/// Copy constructor (deep copy) from 'src', an Array of convertible type.
|
|
template <typename CT>
|
|
inline Array(const Array<CT> &src);
|
|
|
|
/// Destructor
|
|
inline ~Array() { data.Delete(); }
|
|
|
|
/// Assignment operator: deep copy from 'src'.
|
|
Array<T> &operator=(const Array<T> &src) { src.Copy(*this); return *this; }
|
|
|
|
/// Assignment operator (deep copy) from @a src, an Array of convertible type.
|
|
template <typename CT>
|
|
inline Array &operator=(const Array<CT> &src);
|
|
|
|
/// Return the data as 'T *'
|
|
inline operator T *() { return data; }
|
|
|
|
/// Return the data as 'const T *'
|
|
inline operator const T *() const { return data; }
|
|
|
|
/// Returns the data
|
|
inline T *GetData() { return data; }
|
|
/// Returns the data
|
|
inline const T *GetData() const { return data; }
|
|
|
|
/// Return a reference to the Memory object used by the Array.
|
|
Memory<T> &GetMemory() { return data; }
|
|
|
|
/// Return a reference to the Memory object used by the Array, const version.
|
|
const Memory<T> &GetMemory() const { return data; }
|
|
|
|
/// Return the device flag of the Memory object used by the Array
|
|
bool UseDevice() const { return data.UseDevice(); }
|
|
|
|
/// Return true if the data will be deleted by the array
|
|
inline bool OwnsData() const { return data.OwnsHostPtr(); }
|
|
|
|
/// Changes the ownership of the data
|
|
inline void StealData(T **p) { *p = data; data.Reset(); size = 0; }
|
|
|
|
/// NULL-ifies the data
|
|
inline void LoseData() { data.Reset(); size = 0; }
|
|
|
|
/// Make the Array own the data
|
|
void MakeDataOwner() const { data.SetHostPtrOwner(true); }
|
|
|
|
/// Return the logical size of the array.
|
|
inline int Size() const { return size; }
|
|
|
|
/// Change the logical size of the array, keep existing entries.
|
|
inline void SetSize(int nsize);
|
|
|
|
/// Same as SetSize(int) plus initialize new entries with 'initval'.
|
|
inline void SetSize(int nsize, const T &initval);
|
|
|
|
/** @brief Resize the array to size @a nsize using MemoryType @a mt. Note
|
|
that unlike the other versions of SetSize(), the current content of the
|
|
array is not preserved. */
|
|
inline void SetSize(int nsize, MemoryType mt);
|
|
|
|
/** Maximum number of entries the array can store without allocating more
|
|
memory. */
|
|
inline int Capacity() const { return data.Capacity(); }
|
|
|
|
/// Ensures that the allocated size is at least the given size.
|
|
inline void Reserve(int capacity)
|
|
{ if (capacity > Capacity()) { GrowSize(capacity); } }
|
|
|
|
/// Reference access to the ith element.
|
|
inline T & operator[](int i);
|
|
|
|
/// Const reference access to the ith element.
|
|
inline const T &operator[](int i) const;
|
|
|
|
/// Append element 'el' to array, resize if necessary.
|
|
inline int Append(const T & el);
|
|
|
|
/// Append another array to this array, resize if necessary.
|
|
inline int Append(const T *els, int nels);
|
|
|
|
/// Append another array to this array, resize if necessary.
|
|
inline int Append(const Array<T> &els) { return Append(els, els.Size()); }
|
|
|
|
/// Prepend an 'el' to the array, resize if necessary.
|
|
inline int Prepend(const T &el);
|
|
|
|
/// Return the last element in the array.
|
|
inline T &Last();
|
|
|
|
/// Return the last element in the array.
|
|
inline const T &Last() const;
|
|
|
|
/// Append element when it is not yet in the array, return index.
|
|
inline int Union(const T & el);
|
|
|
|
/// Return the first index where 'el' is found; return -1 if not found.
|
|
inline int Find(const T &el) const;
|
|
|
|
/// Do bisection search for 'el' in a sorted array; return -1 if not found.
|
|
inline int FindSorted(const T &el) const;
|
|
|
|
/// Delete the last entry of the array.
|
|
inline void DeleteLast() { if (size > 0) { size--; } }
|
|
|
|
/// Delete the first entry with value == 'el'.
|
|
inline void DeleteFirst(const T &el);
|
|
|
|
/// Delete the whole array.
|
|
inline void DeleteAll();
|
|
|
|
|
|
/// Create a copy of the internal array to the provided @a copy.
|
|
inline void Copy(Array ©) const;
|
|
|
|
/// Make this Array a reference to a pointer.
|
|
inline void MakeRef(T *, int);
|
|
|
|
/// Make this Array a reference to 'master'.
|
|
inline void MakeRef(const Array &master);
|
|
|
|
|
|
/// Copy sub array starting from @a offset out to the provided @a sa.
|
|
inline void GetSubArray(int offset, int sa_size, Array<T> &sa) const;
|
|
|
|
/// Prints array to stream with width elements per row.
|
|
void Print(std::ostream &out = mfem::out, int width = 4) const;
|
|
|
|
/** @brief Save the Array to the stream @a out using the format @a fmt.
|
|
The format @a fmt can be:
|
|
|
|
0 - write the size followed by all entries
|
|
1 - write only the entries
|
|
*/
|
|
void Save(std::ostream &out, int fmt = 0) const;
|
|
|
|
/** @brief Read an Array from the stream @a in using format @a fmt.
|
|
The format @a fmt can be:
|
|
|
|
0 - read the size then the entries
|
|
1 - read Size() entries
|
|
*/
|
|
void Load(std::istream &in, int fmt = 0);
|
|
|
|
/** @brief Set the Array size to @a new_size and read that many entries from
|
|
the stream @a in. */
|
|
void Load(int new_size, std::istream &in)
|
|
{ SetSize(new_size); Load(in, 1); }
|
|
|
|
/** @brief Find the maximal element in the array, using the comparison
|
|
operator `<` for class T. */
|
|
T Max() const;
|
|
|
|
/** @brief Find the minimal element in the array, using the comparison
|
|
operator `<` for class T. */
|
|
T Min() const;
|
|
|
|
/// Sorts the array in ascending order. This requires operator< to be defined for T.
|
|
void Sort() { std::sort((T*)data, data + size); }
|
|
|
|
/// Sorts the array in ascending order using the supplied comparison function object.
|
|
template<class Compare>
|
|
void Sort(Compare cmp) { std::sort((T*)data, data + size, cmp); }
|
|
|
|
/** @brief Removes duplicities from a sorted array. This requires
|
|
operator== to be defined for T. */
|
|
void Unique()
|
|
{
|
|
T* end = std::unique((T*)data, data + size);
|
|
SetSize(end - data);
|
|
}
|
|
|
|
/// Return 1 if the array is sorted from lowest to highest. Otherwise return 0.
|
|
int IsSorted();
|
|
|
|
/// Fill the entries of the array with the cumulative sum of the entries.
|
|
void PartialSum();
|
|
|
|
/// Return the sum of all the array entries using the '+'' operator for class 'T'.
|
|
T Sum();
|
|
|
|
/// Set all entries of the array to the provided constant.
|
|
inline void operator=(const T &a);
|
|
|
|
/// Copy data from a pointer. 'Size()' elements are copied.
|
|
inline void Assign(const T *);
|
|
|
|
/// STL-like copyTo @a dest from begin to end.
|
|
template <typename U>
|
|
inline void CopyTo(U *dest) { std::copy(begin(), end(), dest); }
|
|
|
|
/** @brief Copy from @a src into this array. Copies enough entries to
|
|
fill the Capacity size of this array. Careful this does not update
|
|
the Size to match this Capacity after this.*/
|
|
template <typename U>
|
|
inline void CopyFrom(const U *src)
|
|
{ std::memcpy(begin(), src, MemoryUsage()); }
|
|
|
|
/// STL-like begin. Returns pointer to the first element of the array.
|
|
inline T* begin() { return data; }
|
|
|
|
/// STL-like end. Returns pointer after the last element of the array.
|
|
inline T* end() { return data + size; }
|
|
|
|
/// STL-like begin. Returns const pointer to the first element of the array.
|
|
inline const T* begin() const { return data; }
|
|
|
|
/// STL-like end. Returns const pointer after the last element of the array.
|
|
inline const T* end() const { return data + size; }
|
|
|
|
/// Returns the number of bytes allocated for the array including any reserve.
|
|
long MemoryUsage() const { return Capacity() * sizeof(T); }
|
|
|
|
/// Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
|
|
const T *Read(bool on_dev = true) const
|
|
{ return mfem::Read(data, size, on_dev); }
|
|
|
|
/// Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
|
|
const T *HostRead() const
|
|
{ return mfem::Read(data, size, false); }
|
|
|
|
/// Shortcut for mfem::Write(a.GetMemory(), a.Size(), on_dev).
|
|
T *Write(bool on_dev = true)
|
|
{ return mfem::Write(data, size, on_dev); }
|
|
|
|
/// Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
|
|
T *HostWrite()
|
|
{ return mfem::Write(data, size, false); }
|
|
|
|
/// Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), on_dev).
|
|
T *ReadWrite(bool on_dev = true)
|
|
{ return mfem::ReadWrite(data, size, on_dev); }
|
|
|
|
/// Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
|
|
T *HostReadWrite()
|
|
{ return mfem::ReadWrite(data, size, false); }
|
|
};
|
|
|
|
template <class T>
|
|
inline bool operator==(const Array<T> &LHS, const Array<T> &RHS)
|
|
{
|
|
if ( LHS.Size() != RHS.Size() ) { return false; }
|
|
for (int i=0; i<LHS.Size(); i++)
|
|
{
|
|
if ( LHS[i] != RHS[i] ) { return false; }
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <class T>
|
|
inline bool operator!=(const Array<T> &LHS, const Array<T> &RHS)
|
|
{
|
|
return !( LHS == RHS );
|
|
}
|
|
|
|
|
|
template <class T>
|
|
class Array2D;
|
|
|
|
template <class T>
|
|
void Swap(Array2D<T> &, Array2D<T> &);
|
|
|
|
/// Dynamic 2D array using row-major layout
|
|
template <class T>
|
|
class Array2D
|
|
{
|
|
private:
|
|
friend void Swap<T>(Array2D<T> &, Array2D<T> &);
|
|
|
|
Array<T> array1d;
|
|
int M, N; // number of rows and columns
|
|
|
|
public:
|
|
Array2D() { M = N = 0; }
|
|
Array2D(int m, int n) : array1d(m*n) { M = m; N = n; }
|
|
|
|
void SetSize(int m, int n) { array1d.SetSize(m*n); M = m; N = n; }
|
|
|
|
int NumRows() const { return M; }
|
|
int NumCols() const { return N; }
|
|
|
|
inline const T &operator()(int i, int j) const;
|
|
inline T &operator()(int i, int j);
|
|
|
|
inline const T *operator[](int i) const;
|
|
inline T *operator[](int i);
|
|
|
|
const T *operator()(int i) const { return (*this)[i]; }
|
|
T *operator()(int i) { return (*this)[i]; }
|
|
|
|
const T *GetRow(int i) const { return (*this)[i]; }
|
|
T *GetRow(int i) { return (*this)[i]; }
|
|
|
|
/// Extract a copy of the @a i-th row into the Array @a sa.
|
|
void GetRow(int i, Array<T> &sa) const
|
|
{
|
|
sa.SetSize(N);
|
|
sa.Assign(GetRow(i));
|
|
}
|
|
|
|
/** @brief Save the Array2D to the stream @a out using the format @a fmt.
|
|
The format @a fmt can be:
|
|
|
|
0 - write the number of rows and columns, followed by all entries
|
|
1 - write only the entries, using row-major layout
|
|
*/
|
|
void Save(std::ostream &out, int fmt = 0) const
|
|
{
|
|
if (fmt == 0) { out << NumRows() << ' ' << NumCols() << '\n'; }
|
|
array1d.Save(out, 1);
|
|
}
|
|
|
|
/** @brief Read an Array2D from the stream @a in using format @a fmt.
|
|
The format @a fmt can be:
|
|
|
|
0 - read the number of rows and columns, then the entries
|
|
1 - read NumRows() x NumCols() entries, using row-major layout
|
|
*/
|
|
void Load(std::istream &in, int fmt = 0)
|
|
{
|
|
if (fmt == 0) { in >> M >> N; array1d.SetSize(M*N); }
|
|
array1d.Load(in, 1);
|
|
}
|
|
|
|
/// Read an Array2D from a file
|
|
void Load(const char *filename, int fmt = 0);
|
|
|
|
/** @brief Set the Array2D dimensions to @a new_size0 x @a new_size1 and read
|
|
that many entries from the stream @a in. */
|
|
void Load(int new_size0,int new_size1, std::istream &in)
|
|
{ SetSize(new_size0,new_size1); Load(in, 1); }
|
|
|
|
void Copy(Array2D ©) const
|
|
{ copy.M = M; copy.N = N; array1d.Copy(copy.array1d); }
|
|
|
|
inline void operator=(const T &a)
|
|
{ array1d = a; }
|
|
|
|
/// Make this Array a reference to 'master'
|
|
inline void MakeRef(const Array2D &master)
|
|
{ M = master.M; N = master.N; array1d.MakeRef(master.array1d); }
|
|
|
|
/// Delete all dynamically allocated memory, resetting all dimensions to zero.
|
|
inline void DeleteAll() { M = 0; N = 0; array1d.DeleteAll(); }
|
|
|
|
/// Prints array to stream with width elements per row
|
|
void Print(std::ostream &out = mfem::out, int width = 4);
|
|
};
|
|
|
|
|
|
template <class T>
|
|
class Array3D
|
|
{
|
|
private:
|
|
Array<T> array1d;
|
|
int N2, N3;
|
|
|
|
public:
|
|
Array3D() { N2 = N3 = 0; }
|
|
Array3D(int n1, int n2, int n3)
|
|
: array1d(n1*n2*n3) { N2 = n2; N3 = n3; }
|
|
|
|
void SetSize(int n1, int n2, int n3)
|
|
{ array1d.SetSize(n1*n2*n3); N2 = n2; N3 = n3; }
|
|
|
|
inline const T &operator()(int i, int j, int k) const;
|
|
inline T &operator()(int i, int j, int k);
|
|
};
|
|
|
|
|
|
/** A container for items of type T. Dynamically grows as items are added.
|
|
* Each item is accessible by its index. Items are allocated in larger chunks
|
|
* (blocks), so the 'Append' method is very fast on average.
|
|
*/
|
|
template<typename T>
|
|
class BlockArray
|
|
{
|
|
public:
|
|
BlockArray(int block_size = 16*1024);
|
|
BlockArray(const BlockArray<T> &other); // deep copy
|
|
~BlockArray() { Destroy(); }
|
|
|
|
/// Allocate and construct a new item in the array, return its index.
|
|
int Append();
|
|
|
|
/// Allocate and copy-construct a new item in the array, return its index.
|
|
int Append(const T &item);
|
|
|
|
/// Access item of the array.
|
|
inline T& At(int index)
|
|
{
|
|
CheckIndex(index);
|
|
return blocks[index >> shift][index & mask];
|
|
}
|
|
inline const T& At(int index) const
|
|
{
|
|
CheckIndex(index);
|
|
return blocks[index >> shift][index & mask];
|
|
}
|
|
|
|
/// Access item of the array.
|
|
inline T& operator[](int index) { return At(index); }
|
|
inline const T& operator[](int index) const { return At(index); }
|
|
|
|
/// Return the number of items actually stored.
|
|
int Size() const { return size; }
|
|
|
|
/// Return the current capacity of the BlockArray.
|
|
int Capacity() const { return blocks.Size()*(mask+1); }
|
|
|
|
/// Destroy all items, set size to zero.
|
|
void DeleteAll() { Destroy(); blocks.DeleteAll(); size = 0; }
|
|
|
|
void Swap(BlockArray<T> &other);
|
|
|
|
long MemoryUsage() const;
|
|
|
|
protected:
|
|
template <typename cA, typename cT>
|
|
class iterator_base
|
|
{
|
|
public:
|
|
cT& operator*() const { return *ptr; }
|
|
cT* operator->() const { return ptr; }
|
|
|
|
bool good() const { return !stop; }
|
|
int index() const { return (ptr - ref); }
|
|
|
|
protected:
|
|
cA *array;
|
|
cT *ptr, *b_end, *ref;
|
|
int b_end_idx;
|
|
bool stop;
|
|
|
|
iterator_base() { }
|
|
iterator_base(bool stop) : stop(stop) { }
|
|
iterator_base(cA *a)
|
|
: array(a), ptr(a->blocks[0]), ref(ptr), stop(false)
|
|
{
|
|
b_end_idx = std::min(a->size, a->mask+1);
|
|
b_end = ptr + b_end_idx;
|
|
}
|
|
|
|
void next()
|
|
{
|
|
MFEM_ASSERT(!stop, "invalid use");
|
|
if (++ptr == b_end)
|
|
{
|
|
if (b_end_idx < array->size)
|
|
{
|
|
ptr = &array->At(b_end_idx);
|
|
ref = ptr - b_end_idx;
|
|
b_end_idx = std::min(array->size, (b_end_idx|array->mask) + 1);
|
|
b_end = &array->At(b_end_idx-1) + 1;
|
|
}
|
|
else
|
|
{
|
|
MFEM_ASSERT(b_end_idx == array->size, "invalid use");
|
|
stop = true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
public:
|
|
class iterator : public iterator_base<BlockArray, T>
|
|
{
|
|
protected:
|
|
friend class BlockArray;
|
|
typedef iterator_base<BlockArray, T> base;
|
|
|
|
iterator() { }
|
|
iterator(bool stop) : base(stop) { }
|
|
iterator(BlockArray *a) : base(a) { }
|
|
|
|
public:
|
|
iterator &operator++() { base::next(); return *this; }
|
|
|
|
bool operator==(const iterator &other) const { return base::stop; }
|
|
bool operator!=(const iterator &other) const { return !base::stop; }
|
|
};
|
|
|
|
class const_iterator : public iterator_base<const BlockArray, const T>
|
|
{
|
|
protected:
|
|
friend class BlockArray;
|
|
typedef iterator_base<const BlockArray, const T> base;
|
|
|
|
const_iterator() { }
|
|
const_iterator(bool stop) : base(stop) { }
|
|
const_iterator(const BlockArray *a) : base(a) { }
|
|
|
|
public:
|
|
const_iterator &operator++() { base::next(); return *this; }
|
|
|
|
bool operator==(const const_iterator &other) const { return base::stop; }
|
|
bool operator!=(const const_iterator &other) const { return !base::stop; }
|
|
};
|
|
|
|
iterator begin() { return size ? iterator(this) : iterator(true); }
|
|
iterator end() { return iterator(); }
|
|
|
|
const_iterator cbegin() const
|
|
{ return size ? const_iterator(this) : const_iterator(true); }
|
|
const_iterator cend() const { return const_iterator(); }
|
|
|
|
protected:
|
|
Array<T*> blocks;
|
|
int size, shift, mask;
|
|
|
|
int Alloc();
|
|
|
|
inline void CheckIndex(int index) const
|
|
{
|
|
MFEM_ASSERT(index >= 0 && index < size,
|
|
"Out of bounds access: " << index << ", size = " << size);
|
|
}
|
|
|
|
void Destroy();
|
|
};
|
|
|
|
|
|
/// inlines ///
|
|
|
|
template <class T>
|
|
inline void Swap(T &a, T &b)
|
|
{
|
|
T c = a;
|
|
a = b;
|
|
b = c;
|
|
}
|
|
|
|
template <class T>
|
|
inline void Swap(Array<T> &a, Array<T> &b)
|
|
{
|
|
Swap(a.data, b.data);
|
|
Swap(a.size, b.size);
|
|
}
|
|
|
|
template <class T>
|
|
inline Array<T>::Array(const Array &src)
|
|
: size(src.Size())
|
|
{
|
|
size > 0 ? data.New(size, src.data.GetMemoryType()) : data.Reset();
|
|
data.CopyFrom(src.data, size);
|
|
data.UseDevice(src.data.UseDevice());
|
|
}
|
|
|
|
template <typename T> template <typename CT>
|
|
inline Array<T>::Array(const Array<CT> &src)
|
|
: size(src.Size())
|
|
{
|
|
size > 0 ? data.New(size) : data.Reset();
|
|
for (int i = 0; i < size; i++) { (*this)[i] = T(src[i]); }
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::GrowSize(int minsize)
|
|
{
|
|
const int nsize = std::max(minsize, 2 * data.Capacity());
|
|
Memory<T> p(nsize, data.GetMemoryType());
|
|
p.CopyFrom(data, size);
|
|
p.UseDevice(data.UseDevice());
|
|
data.Delete();
|
|
data = p;
|
|
}
|
|
|
|
template <typename T> template <typename CT>
|
|
inline Array<T> &Array<T>::operator=(const Array<CT> &src)
|
|
{
|
|
SetSize(src.Size());
|
|
for (int i = 0; i < size; i++) { (*this)[i] = T(src[i]); }
|
|
return *this;
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::SetSize(int nsize)
|
|
{
|
|
MFEM_ASSERT( nsize>=0, "Size must be non-negative. It is " << nsize );
|
|
if (nsize > Capacity())
|
|
{
|
|
GrowSize(nsize);
|
|
}
|
|
size = nsize;
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::SetSize(int nsize, const T &initval)
|
|
{
|
|
MFEM_ASSERT( nsize>=0, "Size must be non-negative. It is " << nsize );
|
|
if (nsize > size)
|
|
{
|
|
if (nsize > Capacity())
|
|
{
|
|
GrowSize(nsize);
|
|
}
|
|
for (int i = size; i < nsize; i++)
|
|
{
|
|
data[i] = initval;
|
|
}
|
|
}
|
|
size = nsize;
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::SetSize(int nsize, MemoryType mt)
|
|
{
|
|
MFEM_ASSERT(nsize >= 0, "invalid new size: " << nsize);
|
|
if (mt == data.GetMemoryType())
|
|
{
|
|
if (nsize <= Capacity())
|
|
{
|
|
size = nsize;
|
|
return;
|
|
}
|
|
}
|
|
const bool use_dev = data.UseDevice();
|
|
data.Delete();
|
|
if (nsize > 0)
|
|
{
|
|
data.New(nsize, mt);
|
|
size = nsize;
|
|
}
|
|
else
|
|
{
|
|
data.Reset();
|
|
size = 0;
|
|
}
|
|
data.UseDevice(use_dev);
|
|
}
|
|
|
|
template <class T>
|
|
inline T &Array<T>::operator[](int i)
|
|
{
|
|
MFEM_ASSERT( i>=0 && i<size,
|
|
"Access element " << i << " of array, size = " << size );
|
|
return data[i];
|
|
}
|
|
|
|
template <class T>
|
|
inline const T &Array<T>::operator[](int i) const
|
|
{
|
|
MFEM_ASSERT( i>=0 && i<size,
|
|
"Access element " << i << " of array, size = " << size );
|
|
return data[i];
|
|
}
|
|
|
|
template <class T>
|
|
inline int Array<T>::Append(const T &el)
|
|
{
|
|
SetSize(size+1);
|
|
data[size-1] = el;
|
|
return size;
|
|
}
|
|
|
|
template <class T>
|
|
inline int Array<T>::Append(const T *els, int nels)
|
|
{
|
|
const int old_size = size;
|
|
|
|
SetSize(size + nels);
|
|
for (int i = 0; i < nels; i++)
|
|
{
|
|
data[old_size+i] = els[i];
|
|
}
|
|
return size;
|
|
}
|
|
|
|
template <class T>
|
|
inline int Array<T>::Prepend(const T &el)
|
|
{
|
|
SetSize(size+1);
|
|
for (int i = size-1; i > 0; i--)
|
|
{
|
|
data[i] = data[i-1];
|
|
}
|
|
data[0] = el;
|
|
return size;
|
|
}
|
|
|
|
template <class T>
|
|
inline T &Array<T>::Last()
|
|
{
|
|
MFEM_ASSERT(size > 0, "Array size is zero: " << size);
|
|
return data[size-1];
|
|
}
|
|
|
|
template <class T>
|
|
inline const T &Array<T>::Last() const
|
|
{
|
|
MFEM_ASSERT(size > 0, "Array size is zero: " << size);
|
|
return data[size-1];
|
|
}
|
|
|
|
template <class T>
|
|
inline int Array<T>::Union(const T &el)
|
|
{
|
|
int i = 0;
|
|
while ((i < size) && (data[i] != el)) { i++; }
|
|
if (i == size)
|
|
{
|
|
Append(el);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
template <class T>
|
|
inline int Array<T>::Find(const T &el) const
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
if (data[i] == el) { return i; }
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
template <class T>
|
|
inline int Array<T>::FindSorted(const T &el) const
|
|
{
|
|
const T *begin = data, *end = begin + size;
|
|
const T* first = std::lower_bound(begin, end, el);
|
|
if (first == end || !(*first == el)) { return -1; }
|
|
return first - begin;
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::DeleteFirst(const T &el)
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
if (data[i] == el)
|
|
{
|
|
for (i++; i < size; i++)
|
|
{
|
|
data[i-1] = data[i];
|
|
}
|
|
size--;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::DeleteAll()
|
|
{
|
|
const bool use_dev = data.UseDevice();
|
|
data.Delete();
|
|
data.Reset();
|
|
size = 0;
|
|
data.UseDevice(use_dev);
|
|
}
|
|
|
|
template <typename T>
|
|
inline void Array<T>::Copy(Array ©) const
|
|
{
|
|
copy.SetSize(Size(), data.GetMemoryType());
|
|
data.CopyTo(copy.data, Size());
|
|
copy.data.UseDevice(data.UseDevice());
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::MakeRef(T *p, int s)
|
|
{
|
|
data.Delete();
|
|
data.Wrap(p, s, false);
|
|
size = s;
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::MakeRef(const Array &master)
|
|
{
|
|
data.Delete();
|
|
data = master.data; // note: copies the device flag
|
|
size = master.size;
|
|
data.ClearOwnerFlags();
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::GetSubArray(int offset, int sa_size, Array<T> &sa) const
|
|
{
|
|
sa.SetSize(sa_size);
|
|
for (int i = 0; i < sa_size; i++)
|
|
{
|
|
sa[i] = (*this)[offset+i];
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::operator=(const T &a)
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
data[i] = a;
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
inline void Array<T>::Assign(const T *p)
|
|
{
|
|
data.CopyFromHost(p, Size());
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline const T &Array2D<T>::operator()(int i, int j) const
|
|
{
|
|
MFEM_ASSERT( i>=0 && i< array1d.Size()/N && j>=0 && j<N,
|
|
"Array2D: invalid access of element (" << i << ',' << j
|
|
<< ") in array of size (" << array1d.Size()/N << ',' << N
|
|
<< ")." );
|
|
return array1d[i*N+j];
|
|
}
|
|
|
|
template <class T>
|
|
inline T &Array2D<T>::operator()(int i, int j)
|
|
{
|
|
MFEM_ASSERT( i>=0 && i< array1d.Size()/N && j>=0 && j<N,
|
|
"Array2D: invalid access of element (" << i << ',' << j
|
|
<< ") in array of size (" << array1d.Size()/N << ',' << N
|
|
<< ")." );
|
|
return array1d[i*N+j];
|
|
}
|
|
|
|
template <class T>
|
|
inline const T *Array2D<T>::operator[](int i) const
|
|
{
|
|
MFEM_ASSERT( i>=0 && i< array1d.Size()/N,
|
|
"Array2D: invalid access of row " << i << " in array with "
|
|
<< array1d.Size()/N << " rows.");
|
|
return &array1d[i*N];
|
|
}
|
|
|
|
template <class T>
|
|
inline T *Array2D<T>::operator[](int i)
|
|
{
|
|
MFEM_ASSERT( i>=0 && i< array1d.Size()/N,
|
|
"Array2D: invalid access of row " << i << " in array with "
|
|
<< array1d.Size()/N << " rows.");
|
|
return &array1d[i*N];
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline void Swap(Array2D<T> &a, Array2D<T> &b)
|
|
{
|
|
Swap(a.array1d, b.array1d);
|
|
Swap(a.N, b.N);
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline const T &Array3D<T>::operator()(int i, int j, int k) const
|
|
{
|
|
MFEM_ASSERT(i >= 0 && i < array1d.Size() / N2 / N3 && j >= 0 && j < N2
|
|
&& k >= 0 && k < N3,
|
|
"Array3D: invalid access of element ("
|
|
<< i << ',' << j << ',' << k << ") in array of size ("
|
|
<< array1d.Size() / N2 / N3 << ',' << N2 << ',' << N3 << ").");
|
|
return array1d[(i*N2+j)*N3+k];
|
|
}
|
|
|
|
template <class T>
|
|
inline T &Array3D<T>::operator()(int i, int j, int k)
|
|
{
|
|
MFEM_ASSERT(i >= 0 && i < array1d.Size() / N2 / N3 && j >= 0 && j < N2
|
|
&& k >= 0 && k < N3,
|
|
"Array3D: invalid access of element ("
|
|
<< i << ',' << j << ',' << k << ") in array of size ("
|
|
<< array1d.Size() / N2 / N3 << ',' << N2 << ',' << N3 << ").");
|
|
return array1d[(i*N2+j)*N3+k];
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
BlockArray<T>::BlockArray(int block_size)
|
|
{
|
|
mask = block_size-1;
|
|
MFEM_VERIFY(!(block_size & mask), "block_size must be a power of two.");
|
|
|
|
size = shift = 0;
|
|
while ((1 << shift) < block_size) { shift++; }
|
|
}
|
|
|
|
template<typename T>
|
|
BlockArray<T>::BlockArray(const BlockArray<T> &other)
|
|
{
|
|
blocks.SetSize(other.blocks.Size());
|
|
|
|
size = other.size;
|
|
shift = other.shift;
|
|
mask = other.mask;
|
|
|
|
int bsize = mask+1;
|
|
for (int i = 0; i < blocks.Size(); i++)
|
|
{
|
|
blocks[i] = (T*) new char[bsize * sizeof(T)];
|
|
}
|
|
|
|
// copy all items
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
new (&At(i)) T(other[i]);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
int BlockArray<T>::Alloc()
|
|
{
|
|
int bsize = mask+1;
|
|
if (size >= blocks.Size() * bsize)
|
|
{
|
|
T* new_block = (T*) new char[bsize * sizeof(T)];
|
|
blocks.Append(new_block);
|
|
}
|
|
return size++;
|
|
}
|
|
|
|
template<typename T>
|
|
int BlockArray<T>::Append()
|
|
{
|
|
int index = Alloc();
|
|
new (&At(index)) T();
|
|
return index;
|
|
}
|
|
|
|
template<typename T>
|
|
int BlockArray<T>::Append(const T &item)
|
|
{
|
|
int index = Alloc();
|
|
new (&At(index)) T(item);
|
|
return index;
|
|
}
|
|
|
|
template<typename T>
|
|
void BlockArray<T>::Swap(BlockArray<T> &other)
|
|
{
|
|
mfem::Swap(blocks, other.blocks);
|
|
std::swap(size, other.size);
|
|
std::swap(shift, other.shift);
|
|
std::swap(mask, other.mask);
|
|
}
|
|
|
|
template<typename T>
|
|
long BlockArray<T>::MemoryUsage() const
|
|
{
|
|
return blocks.Size()*(mask+1)*sizeof(T) +
|
|
blocks.MemoryUsage();
|
|
}
|
|
|
|
template<typename T>
|
|
void BlockArray<T>::Destroy()
|
|
{
|
|
int bsize = size & mask;
|
|
for (int i = blocks.Size(); i != 0; )
|
|
{
|
|
T *block = blocks[--i];
|
|
for (int j = bsize; j != 0; )
|
|
{
|
|
block[--j].~T();
|
|
}
|
|
delete [] (char*) block;
|
|
bsize = mask+1;
|
|
}
|
|
}
|
|
|
|
} // namespace mfem
|
|
|
|
#endif
|