MFEM  v4.2.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
array.hpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #ifndef MFEM_ARRAY
13 #define MFEM_ARRAY
14 
15 #include "../config/config.hpp"
16 #include "mem_manager.hpp"
17 #include "device.hpp"
18 #include "error.hpp"
19 #include "globals.hpp"
20 
21 #include <iostream>
22 #include <cstdlib>
23 #include <cstring>
24 #include <algorithm>
25 
26 namespace mfem
27 {
28 
29 template <class T>
30 class Array;
31 
32 template <class T>
33 void Swap(Array<T> &, Array<T> &);
34 
35 /**
36  Abstract data type Array.
37 
38  Array<T> is an automatically increasing array containing elements of the
39  generic type T, which must be a POD (plain old data) type. The allocated size
40  may be larger then the logical size of the array. The elements can be
41  accessed by the [] operator, the range is 0 to size-1.
42 */
43 template <class T>
44 class Array
45 {
46 protected:
47  /// Pointer to data
49  /// Size of the array
50  int size;
51 
52  inline void GrowSize(int minsize);
53 
54 public:
55  friend void Swap<T>(Array<T> &, Array<T> &);
56 
57  /// Creates an empty array
58  inline Array() : size(0) { data.Reset(); }
59 
60  /// Creates an empty array with a given MemoryType
61  inline Array(MemoryType mt) : size(0) { data.Reset(mt); }
62 
63  /// Creates array of @a asize elements
64  explicit inline Array(int asize)
65  : size(asize) { asize > 0 ? data.New(asize) : data.Reset(); }
66 
67  /** @brief Creates array using an existing c-array of asize elements;
68  allocsize is set to -asize to indicate that the data will not
69  be deleted. */
70  inline Array(T *_data, int asize)
71  { data.Wrap(_data, asize, false); size = asize; }
72 
73  /// Copy constructor: deep copy from @a src
74  /** This method supports source arrays using any MemoryType. */
75  inline Array(const Array &src);
76 
77  /// Copy constructor (deep copy) from 'src', an Array of convertible type.
78  template <typename CT>
79  inline Array(const Array<CT> &src);
80 
81  /// Destructor
82  inline ~Array() { data.Delete(); }
83 
84  /// Assignment operator: deep copy from 'src'.
85  Array<T> &operator=(const Array<T> &src) { src.Copy(*this); return *this; }
86 
87  /// Assignment operator (deep copy) from @a src, an Array of convertible type.
88  template <typename CT>
89  inline Array &operator=(const Array<CT> &src);
90 
91  /// Return the data as 'T *'
92  inline operator T *() { return data; }
93 
94  /// Return the data as 'const T *'
95  inline operator const T *() const { return data; }
96 
97  /// Returns the data
98  inline T *GetData() { return data; }
99  /// Returns the data
100  inline const T *GetData() const { return data; }
101 
102  /// Return a reference to the Memory object used by the Array.
103  Memory<T> &GetMemory() { return data; }
104 
105  /// Return a reference to the Memory object used by the Array, const version.
106  const Memory<T> &GetMemory() const { return data; }
107 
108  /// Return the device flag of the Memory object used by the Array
109  bool UseDevice() const { return data.UseDevice(); }
110 
111  /// Return true if the data will be deleted by the array
112  inline bool OwnsData() const { return data.OwnsHostPtr(); }
113 
114  /// Changes the ownership of the data
115  inline void StealData(T **p) { *p = data; data.Reset(); size = 0; }
116 
117  /// NULL-ifies the data
118  inline void LoseData() { data.Reset(); size = 0; }
119 
120  /// Make the Array own the data
121  void MakeDataOwner() const { data.SetHostPtrOwner(true); }
122 
123  /// Return the logical size of the array.
124  inline int Size() const { return size; }
125 
126  /// Change the logical size of the array, keep existing entries.
127  inline void SetSize(int nsize);
128 
129  /// Same as SetSize(int) plus initialize new entries with 'initval'.
130  inline void SetSize(int nsize, const T &initval);
131 
132  /** @brief Resize the array to size @a nsize using MemoryType @a mt. Note
133  that unlike the other versions of SetSize(), the current content of the
134  array is not preserved. */
135  inline void SetSize(int nsize, MemoryType mt);
136 
137  /** Maximum number of entries the array can store without allocating more
138  memory. */
139  inline int Capacity() const { return data.Capacity(); }
140 
141  /// Ensures that the allocated size is at least the given size.
142  inline void Reserve(int capacity)
143  { if (capacity > Capacity()) { GrowSize(capacity); } }
144 
145  /// Reference access to the ith element.
146  inline T & operator[](int i);
147 
148  /// Const reference access to the ith element.
149  inline const T &operator[](int i) const;
150 
151  /// Append element 'el' to array, resize if necessary.
152  inline int Append(const T & el);
153 
154  /// Append another array to this array, resize if necessary.
155  inline int Append(const T *els, int nels);
156 
157  /// Append another array to this array, resize if necessary.
158  inline int Append(const Array<T> &els) { return Append(els, els.Size()); }
159 
160  /// Prepend an 'el' to the array, resize if necessary.
161  inline int Prepend(const T &el);
162 
163  /// Return the last element in the array.
164  inline T &Last();
165 
166  /// Return the last element in the array.
167  inline const T &Last() const;
168 
169  /// Append element when it is not yet in the array, return index.
170  inline int Union(const T & el);
171 
172  /// Return the first index where 'el' is found; return -1 if not found.
173  inline int Find(const T &el) const;
174 
175  /// Do bisection search for 'el' in a sorted array; return -1 if not found.
176  inline int FindSorted(const T &el) const;
177 
178  /// Delete the last entry of the array.
179  inline void DeleteLast() { if (size > 0) { size--; } }
180 
181  /// Delete the first entry with value == 'el'.
182  inline void DeleteFirst(const T &el);
183 
184  /// Delete the whole array.
185  inline void DeleteAll();
186 
187 
188  /// Create a copy of the internal array to the provided @a copy.
189  inline void Copy(Array &copy) const;
190 
191  /// Make this Array a reference to a pointer.
192  inline void MakeRef(T *, int);
193 
194  /// Make this Array a reference to 'master'.
195  inline void MakeRef(const Array &master);
196 
197 
198  /// Copy sub array starting from @a offset out to the provided @a sa.
199  inline void GetSubArray(int offset, int sa_size, Array<T> &sa) const;
200 
201  /// Prints array to stream with width elements per row.
202  void Print(std::ostream &out = mfem::out, int width = 4) const;
203 
204  /** @brief Save the Array to the stream @a out using the format @a fmt.
205  The format @a fmt can be:
206 
207  0 - write the size followed by all entries
208  1 - write only the entries
209  */
210  void Save(std::ostream &out, int fmt = 0) const;
211 
212  /** @brief Read an Array from the stream @a in using format @a fmt.
213  The format @a fmt can be:
214 
215  0 - read the size then the entries
216  1 - read Size() entries
217  */
218  void Load(std::istream &in, int fmt = 0);
219 
220  /** @brief Set the Array size to @a new_size and read that many entries from
221  the stream @a in. */
222  void Load(int new_size, std::istream &in)
223  { SetSize(new_size); Load(in, 1); }
224 
225  /** @brief Find the maximal element in the array, using the comparison
226  operator `<` for class T. */
227  T Max() const;
228 
229  /** @brief Find the minimal element in the array, using the comparison
230  operator `<` for class T. */
231  T Min() const;
232 
233  /// Sorts the array in ascending order. This requires operator< to be defined for T.
234  void Sort() { std::sort((T*)data, data + size); }
235 
236  /// Sorts the array in ascending order using the supplied comparison function object.
237  template<class Compare>
238  void Sort(Compare cmp) { std::sort((T*)data, data + size, cmp); }
239 
240  /** @brief Removes duplicities from a sorted array. This requires
241  operator== to be defined for T. */
242  void Unique()
243  {
244  T* end = std::unique((T*)data, data + size);
245  SetSize(end - data);
246  }
247 
248  /// Return 1 if the array is sorted from lowest to highest. Otherwise return 0.
249  int IsSorted();
250 
251  /// Fill the entries of the array with the cumulative sum of the entries.
252  void PartialSum();
253 
254  /// Return the sum of all the array entries using the '+'' operator for class 'T'.
255  T Sum();
256 
257  /// Set all entries of the array to the provided constant.
258  inline void operator=(const T &a);
259 
260  /// Copy data from a pointer. 'Size()' elements are copied.
261  inline void Assign(const T *);
262 
263  /// STL-like copyTo @a dest from begin to end.
264  template <typename U>
265  inline void CopyTo(U *dest) { std::copy(begin(), end(), dest); }
266 
267  /** @brief Copy from @a src into this array. Copies enough entries to
268  fill the Capacity size of this array. Careful this does not update
269  the Size to match this Capacity after this.*/
270  template <typename U>
271  inline void CopyFrom(const U *src)
272  { std::memcpy(begin(), src, MemoryUsage()); }
273 
274  /// STL-like begin. Returns pointer to the first element of the array.
275  inline T* begin() { return data; }
276 
277  /// STL-like end. Returns pointer after the last element of the array.
278  inline T* end() { return data + size; }
279 
280  /// STL-like begin. Returns const pointer to the first element of the array.
281  inline const T* begin() const { return data; }
282 
283  /// STL-like end. Returns const pointer after the last element of the array.
284  inline const T* end() const { return data + size; }
285 
286  /// Returns the number of bytes allocated for the array including any reserve.
287  long MemoryUsage() const { return Capacity() * sizeof(T); }
288 
289  /// Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
290  const T *Read(bool on_dev = true) const
291  { return mfem::Read(data, size, on_dev); }
292 
293  /// Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
294  const T *HostRead() const
295  { return mfem::Read(data, size, false); }
296 
297  /// Shortcut for mfem::Write(a.GetMemory(), a.Size(), on_dev).
298  T *Write(bool on_dev = true)
299  { return mfem::Write(data, size, on_dev); }
300 
301  /// Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
303  { return mfem::Write(data, size, false); }
304 
305  /// Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), on_dev).
306  T *ReadWrite(bool on_dev = true)
307  { return mfem::ReadWrite(data, size, on_dev); }
308 
309  /// Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
311  { return mfem::ReadWrite(data, size, false); }
312 };
313 
314 template <class T>
315 inline bool operator==(const Array<T> &LHS, const Array<T> &RHS)
316 {
317  if ( LHS.Size() != RHS.Size() ) { return false; }
318  for (int i=0; i<LHS.Size(); i++)
319  {
320  if ( LHS[i] != RHS[i] ) { return false; }
321  }
322  return true;
323 }
324 
325 template <class T>
326 inline bool operator!=(const Array<T> &LHS, const Array<T> &RHS)
327 {
328  return !( LHS == RHS );
329 }
330 
331 
332 template <class T>
333 class Array2D;
334 
335 template <class T>
336 void Swap(Array2D<T> &, Array2D<T> &);
337 
338 /// Dynamic 2D array using row-major layout
339 template <class T>
340 class Array2D
341 {
342 private:
343  friend void Swap<T>(Array2D<T> &, Array2D<T> &);
344 
345  Array<T> array1d;
346  int M, N; // number of rows and columns
347 
348 public:
349  Array2D() { M = N = 0; }
350  Array2D(int m, int n) : array1d(m*n) { M = m; N = n; }
351 
352  void SetSize(int m, int n) { array1d.SetSize(m*n); M = m; N = n; }
353 
354  int NumRows() const { return M; }
355  int NumCols() const { return N; }
356 
357  inline const T &operator()(int i, int j) const;
358  inline T &operator()(int i, int j);
359 
360  inline const T *operator[](int i) const;
361  inline T *operator[](int i);
362 
363  const T *operator()(int i) const { return (*this)[i]; }
364  T *operator()(int i) { return (*this)[i]; }
365 
366  const T *GetRow(int i) const { return (*this)[i]; }
367  T *GetRow(int i) { return (*this)[i]; }
368 
369  /// Extract a copy of the @a i-th row into the Array @a sa.
370  void GetRow(int i, Array<T> &sa) const
371  {
372  sa.SetSize(N);
373  sa.Assign(GetRow(i));
374  }
375 
376  /** @brief Save the Array2D to the stream @a out using the format @a fmt.
377  The format @a fmt can be:
378 
379  0 - write the number of rows and columns, followed by all entries
380  1 - write only the entries, using row-major layout
381  */
382  void Save(std::ostream &out, int fmt = 0) const
383  {
384  if (fmt == 0) { out << NumRows() << ' ' << NumCols() << '\n'; }
385  array1d.Save(out, 1);
386  }
387 
388  /** @brief Read an Array2D from the stream @a in using format @a fmt.
389  The format @a fmt can be:
390 
391  0 - read the number of rows and columns, then the entries
392  1 - read NumRows() x NumCols() entries, using row-major layout
393  */
394  void Load(std::istream &in, int fmt = 0)
395  {
396  if (fmt == 0) { in >> M >> N; array1d.SetSize(M*N); }
397  array1d.Load(in, 1);
398  }
399 
400  /// Read an Array2D from a file
401  void Load(const char *filename, int fmt = 0);
402 
403  /** @brief Set the Array2D dimensions to @a new_size0 x @a new_size1 and read
404  that many entries from the stream @a in. */
405  void Load(int new_size0,int new_size1, std::istream &in)
406  { SetSize(new_size0,new_size1); Load(in, 1); }
407 
408  void Copy(Array2D &copy) const
409  { copy.M = M; copy.N = N; array1d.Copy(copy.array1d); }
410 
411  inline void operator=(const T &a)
412  { array1d = a; }
413 
414  inline Array2D& operator=(const Array2D &a) = default;
415 
416  /// Make this Array a reference to 'master'
417  inline void MakeRef(const Array2D &master)
418  { M = master.M; N = master.N; array1d.MakeRef(master.array1d); }
419 
420  /// Delete all dynamically allocated memory, resetting all dimensions to zero.
421  inline void DeleteAll() { M = 0; N = 0; array1d.DeleteAll(); }
422 
423  /// Prints array to stream with width elements per row
424  void Print(std::ostream &out = mfem::out, int width = 4);
425 };
426 
427 
428 template <class T>
429 class Array3D
430 {
431 private:
432  Array<T> array1d;
433  int N2, N3;
434 
435 public:
436  Array3D() { N2 = N3 = 0; }
437  Array3D(int n1, int n2, int n3)
438  : array1d(n1*n2*n3) { N2 = n2; N3 = n3; }
439 
440  void SetSize(int n1, int n2, int n3)
441  { array1d.SetSize(n1*n2*n3); N2 = n2; N3 = n3; }
442 
443  inline const T &operator()(int i, int j, int k) const;
444  inline T &operator()(int i, int j, int k);
445 };
446 
447 
448 /** A container for items of type T. Dynamically grows as items are added.
449  * Each item is accessible by its index. Items are allocated in larger chunks
450  * (blocks), so the 'Append' method is very fast on average.
451  */
452 template<typename T>
454 {
455 public:
456  BlockArray(int block_size = 16*1024);
457  BlockArray(const BlockArray<T> &other); // deep copy
459 
460  /// Allocate and construct a new item in the array, return its index.
461  int Append();
462 
463  /// Allocate and copy-construct a new item in the array, return its index.
464  int Append(const T &item);
465 
466  /// Access item of the array.
467  inline T& At(int index)
468  {
469  CheckIndex(index);
470  return blocks[index >> shift][index & mask];
471  }
472  inline const T& At(int index) const
473  {
474  CheckIndex(index);
475  return blocks[index >> shift][index & mask];
476  }
477 
478  /// Access item of the array.
479  inline T& operator[](int index) { return At(index); }
480  inline const T& operator[](int index) const { return At(index); }
481 
482  /// Return the number of items actually stored.
483  int Size() const { return size; }
484 
485  /// Return the current capacity of the BlockArray.
486  int Capacity() const { return blocks.Size()*(mask+1); }
487 
488  /// Destroy all items, set size to zero.
489  void DeleteAll() { Destroy(); blocks.DeleteAll(); size = 0; }
490 
491  void Swap(BlockArray<T> &other);
492 
493  long MemoryUsage() const;
494 
495 protected:
496  template <typename cA, typename cT>
498  {
499  public:
500  cT& operator*() const { return *ptr; }
501  cT* operator->() const { return ptr; }
502 
503  bool good() const { return !stop; }
504  int index() const { return (ptr - ref); }
505 
506  protected:
507  cA *array;
508  cT *ptr, *b_end, *ref;
510  bool stop;
511 
513  iterator_base(bool stop) : stop(stop) { }
515  : array(a), ptr(a->blocks[0]), ref(ptr), stop(false)
516  {
517  b_end_idx = std::min(a->size, a->mask+1);
518  b_end = ptr + b_end_idx;
519  }
520 
521  void next()
522  {
523  MFEM_ASSERT(!stop, "invalid use");
524  if (++ptr == b_end)
525  {
526  if (b_end_idx < array->size)
527  {
528  ptr = &array->At(b_end_idx);
529  ref = ptr - b_end_idx;
530  b_end_idx = std::min(array->size, (b_end_idx|array->mask) + 1);
531  b_end = &array->At(b_end_idx-1) + 1;
532  }
533  else
534  {
535  MFEM_ASSERT(b_end_idx == array->size, "invalid use");
536  stop = true;
537  }
538  }
539  }
540  };
541 
542 public:
543  class iterator : public iterator_base<BlockArray, T>
544  {
545  protected:
546  friend class BlockArray;
548 
549  iterator() { }
550  iterator(bool stop) : base(stop) { }
552 
553  public:
554  iterator &operator++() { base::next(); return *this; }
555 
556  bool operator==(const iterator &other) const { return base::stop; }
557  bool operator!=(const iterator &other) const { return !base::stop; }
558  };
559 
560  class const_iterator : public iterator_base<const BlockArray, const T>
561  {
562  protected:
563  friend class BlockArray;
565 
567  const_iterator(bool stop) : base(stop) { }
568  const_iterator(const BlockArray *a) : base(a) { }
569 
570  public:
571  const_iterator &operator++() { base::next(); return *this; }
572 
573  bool operator==(const const_iterator &other) const { return base::stop; }
574  bool operator!=(const const_iterator &other) const { return !base::stop; }
575  };
576 
577  iterator begin() { return size ? iterator(this) : iterator(true); }
578  iterator end() { return iterator(); }
579 
580  const_iterator cbegin() const
581  { return size ? const_iterator(this) : const_iterator(true); }
582  const_iterator cend() const { return const_iterator(); }
583 
584 protected:
586  int size, shift, mask;
587 
588  int Alloc();
589 
590  inline void CheckIndex(int index) const
591  {
592  MFEM_ASSERT(index >= 0 && index < size,
593  "Out of bounds access: " << index << ", size = " << size);
594  }
595 
596  void Destroy();
597 };
598 
599 
600 /// inlines ///
601 
602 template <class T>
603 inline void Swap(T &a, T &b)
604 {
605  T c = a;
606  a = b;
607  b = c;
608 }
609 
610 template <class T>
611 inline void Swap(Array<T> &a, Array<T> &b)
612 {
613  Swap(a.data, b.data);
614  Swap(a.size, b.size);
615 }
616 
617 template <class T>
618 inline Array<T>::Array(const Array &src)
619  : size(src.Size())
620 {
621  size > 0 ? data.New(size, src.data.GetMemoryType()) : data.Reset();
622  data.CopyFrom(src.data, size);
623  data.UseDevice(src.data.UseDevice());
624 }
625 
626 template <typename T> template <typename CT>
627 inline Array<T>::Array(const Array<CT> &src)
628  : size(src.Size())
629 {
630  size > 0 ? data.New(size) : data.Reset();
631  for (int i = 0; i < size; i++) { (*this)[i] = T(src[i]); }
632 }
633 
634 template <class T>
635 inline void Array<T>::GrowSize(int minsize)
636 {
637  const int nsize = std::max(minsize, 2 * data.Capacity());
638  Memory<T> p(nsize, data.GetMemoryType());
639  p.CopyFrom(data, size);
640  p.UseDevice(data.UseDevice());
641  data.Delete();
642  data = p;
643 }
644 
645 template <typename T> template <typename CT>
647 {
648  SetSize(src.Size());
649  for (int i = 0; i < size; i++) { (*this)[i] = T(src[i]); }
650  return *this;
651 }
652 
653 template <class T>
654 inline void Array<T>::SetSize(int nsize)
655 {
656  MFEM_ASSERT( nsize>=0, "Size must be non-negative. It is " << nsize );
657  if (nsize > Capacity())
658  {
659  GrowSize(nsize);
660  }
661  size = nsize;
662 }
663 
664 template <class T>
665 inline void Array<T>::SetSize(int nsize, const T &initval)
666 {
667  MFEM_ASSERT( nsize>=0, "Size must be non-negative. It is " << nsize );
668  if (nsize > size)
669  {
670  if (nsize > Capacity())
671  {
672  GrowSize(nsize);
673  }
674  for (int i = size; i < nsize; i++)
675  {
676  data[i] = initval;
677  }
678  }
679  size = nsize;
680 }
681 
682 template <class T>
683 inline void Array<T>::SetSize(int nsize, MemoryType mt)
684 {
685  MFEM_ASSERT(nsize >= 0, "invalid new size: " << nsize);
686  if (mt == data.GetMemoryType())
687  {
688  if (nsize <= Capacity())
689  {
690  size = nsize;
691  return;
692  }
693  }
694  const bool use_dev = data.UseDevice();
695  data.Delete();
696  if (nsize > 0)
697  {
698  data.New(nsize, mt);
699  size = nsize;
700  }
701  else
702  {
703  data.Reset();
704  size = 0;
705  }
706  data.UseDevice(use_dev);
707 }
708 
709 template <class T>
710 inline T &Array<T>::operator[](int i)
711 {
712  MFEM_ASSERT( i>=0 && i<size,
713  "Access element " << i << " of array, size = " << size );
714  return data[i];
715 }
716 
717 template <class T>
718 inline const T &Array<T>::operator[](int i) const
719 {
720  MFEM_ASSERT( i>=0 && i<size,
721  "Access element " << i << " of array, size = " << size );
722  return data[i];
723 }
724 
725 template <class T>
726 inline int Array<T>::Append(const T &el)
727 {
728  SetSize(size+1);
729  data[size-1] = el;
730  return size;
731 }
732 
733 template <class T>
734 inline int Array<T>::Append(const T *els, int nels)
735 {
736  const int old_size = size;
737 
738  SetSize(size + nels);
739  for (int i = 0; i < nels; i++)
740  {
741  data[old_size+i] = els[i];
742  }
743  return size;
744 }
745 
746 template <class T>
747 inline int Array<T>::Prepend(const T &el)
748 {
749  SetSize(size+1);
750  for (int i = size-1; i > 0; i--)
751  {
752  data[i] = data[i-1];
753  }
754  data[0] = el;
755  return size;
756 }
757 
758 template <class T>
759 inline T &Array<T>::Last()
760 {
761  MFEM_ASSERT(size > 0, "Array size is zero: " << size);
762  return data[size-1];
763 }
764 
765 template <class T>
766 inline const T &Array<T>::Last() const
767 {
768  MFEM_ASSERT(size > 0, "Array size is zero: " << size);
769  return data[size-1];
770 }
771 
772 template <class T>
773 inline int Array<T>::Union(const T &el)
774 {
775  int i = 0;
776  while ((i < size) && (data[i] != el)) { i++; }
777  if (i == size)
778  {
779  Append(el);
780  }
781  return i;
782 }
783 
784 template <class T>
785 inline int Array<T>::Find(const T &el) const
786 {
787  for (int i = 0; i < size; i++)
788  {
789  if (data[i] == el) { return i; }
790  }
791  return -1;
792 }
793 
794 template <class T>
795 inline int Array<T>::FindSorted(const T &el) const
796 {
797  const T *begin = data, *end = begin + size;
798  const T* first = std::lower_bound(begin, end, el);
799  if (first == end || !(*first == el)) { return -1; }
800  return first - begin;
801 }
802 
803 template <class T>
804 inline void Array<T>::DeleteFirst(const T &el)
805 {
806  for (int i = 0; i < size; i++)
807  {
808  if (data[i] == el)
809  {
810  for (i++; i < size; i++)
811  {
812  data[i-1] = data[i];
813  }
814  size--;
815  return;
816  }
817  }
818 }
819 
820 template <class T>
821 inline void Array<T>::DeleteAll()
822 {
823  const bool use_dev = data.UseDevice();
824  data.Delete();
825  data.Reset();
826  size = 0;
827  data.UseDevice(use_dev);
828 }
829 
830 template <typename T>
831 inline void Array<T>::Copy(Array &copy) const
832 {
833  copy.SetSize(Size(), data.GetMemoryType());
834  data.CopyTo(copy.data, Size());
835  copy.data.UseDevice(data.UseDevice());
836 }
837 
838 template <class T>
839 inline void Array<T>::MakeRef(T *p, int s)
840 {
841  data.Delete();
842  data.Wrap(p, s, false);
843  size = s;
844 }
845 
846 template <class T>
847 inline void Array<T>::MakeRef(const Array &master)
848 {
849  data.Delete();
850  data = master.data; // note: copies the device flag
851  size = master.size;
852  data.ClearOwnerFlags();
853 }
854 
855 template <class T>
856 inline void Array<T>::GetSubArray(int offset, int sa_size, Array<T> &sa) const
857 {
858  sa.SetSize(sa_size);
859  for (int i = 0; i < sa_size; i++)
860  {
861  sa[i] = (*this)[offset+i];
862  }
863 }
864 
865 template <class T>
866 inline void Array<T>::operator=(const T &a)
867 {
868  for (int i = 0; i < size; i++)
869  {
870  data[i] = a;
871  }
872 }
873 
874 template <class T>
875 inline void Array<T>::Assign(const T *p)
876 {
877  data.CopyFromHost(p, Size());
878 }
879 
880 
881 template <class T>
882 inline const T &Array2D<T>::operator()(int i, int j) const
883 {
884  MFEM_ASSERT( i>=0 && i< array1d.Size()/N && j>=0 && j<N,
885  "Array2D: invalid access of element (" << i << ',' << j
886  << ") in array of size (" << array1d.Size()/N << ',' << N
887  << ")." );
888  return array1d[i*N+j];
889 }
890 
891 template <class T>
892 inline T &Array2D<T>::operator()(int i, int j)
893 {
894  MFEM_ASSERT( i>=0 && i< array1d.Size()/N && j>=0 && j<N,
895  "Array2D: invalid access of element (" << i << ',' << j
896  << ") in array of size (" << array1d.Size()/N << ',' << N
897  << ")." );
898  return array1d[i*N+j];
899 }
900 
901 template <class T>
902 inline const T *Array2D<T>::operator[](int i) const
903 {
904  MFEM_ASSERT( i>=0 && i< array1d.Size()/N,
905  "Array2D: invalid access of row " << i << " in array with "
906  << array1d.Size()/N << " rows.");
907  return &array1d[i*N];
908 }
909 
910 template <class T>
911 inline T *Array2D<T>::operator[](int i)
912 {
913  MFEM_ASSERT( i>=0 && i< array1d.Size()/N,
914  "Array2D: invalid access of row " << i << " in array with "
915  << array1d.Size()/N << " rows.");
916  return &array1d[i*N];
917 }
918 
919 
920 template <class T>
921 inline void Swap(Array2D<T> &a, Array2D<T> &b)
922 {
923  Swap(a.array1d, b.array1d);
924  Swap(a.N, b.N);
925 }
926 
927 
928 template <class T>
929 inline const T &Array3D<T>::operator()(int i, int j, int k) const
930 {
931  MFEM_ASSERT(i >= 0 && i < array1d.Size() / N2 / N3 && j >= 0 && j < N2
932  && k >= 0 && k < N3,
933  "Array3D: invalid access of element ("
934  << i << ',' << j << ',' << k << ") in array of size ("
935  << array1d.Size() / N2 / N3 << ',' << N2 << ',' << N3 << ").");
936  return array1d[(i*N2+j)*N3+k];
937 }
938 
939 template <class T>
940 inline T &Array3D<T>::operator()(int i, int j, int k)
941 {
942  MFEM_ASSERT(i >= 0 && i < array1d.Size() / N2 / N3 && j >= 0 && j < N2
943  && k >= 0 && k < N3,
944  "Array3D: invalid access of element ("
945  << i << ',' << j << ',' << k << ") in array of size ("
946  << array1d.Size() / N2 / N3 << ',' << N2 << ',' << N3 << ").");
947  return array1d[(i*N2+j)*N3+k];
948 }
949 
950 
951 template<typename T>
953 {
954  mask = block_size-1;
955  MFEM_VERIFY(!(block_size & mask), "block_size must be a power of two.");
956 
957  size = shift = 0;
958  while ((1 << shift) < block_size) { shift++; }
959 }
960 
961 template<typename T>
963 {
964  blocks.SetSize(other.blocks.Size());
965 
966  size = other.size;
967  shift = other.shift;
968  mask = other.mask;
969 
970  int bsize = mask+1;
971  for (int i = 0; i < blocks.Size(); i++)
972  {
973  blocks[i] = (T*) new char[bsize * sizeof(T)];
974  }
975 
976  // copy all items
977  for (int i = 0; i < size; i++)
978  {
979  new (&At(i)) T(other[i]);
980  }
981 }
982 
983 template<typename T>
985 {
986  int bsize = mask+1;
987  if (size >= blocks.Size() * bsize)
988  {
989  T* new_block = (T*) new char[bsize * sizeof(T)];
990  blocks.Append(new_block);
991  }
992  return size++;
993 }
994 
995 template<typename T>
997 {
998  int index = Alloc();
999  new (&At(index)) T();
1000  return index;
1001 }
1002 
1003 template<typename T>
1004 int BlockArray<T>::Append(const T &item)
1005 {
1006  int index = Alloc();
1007  new (&At(index)) T(item);
1008  return index;
1009 }
1010 
1011 template<typename T>
1013 {
1014  mfem::Swap(blocks, other.blocks);
1015  std::swap(size, other.size);
1016  std::swap(shift, other.shift);
1017  std::swap(mask, other.mask);
1018 }
1019 
1020 template<typename T>
1022 {
1023  return blocks.Size()*(mask+1)*sizeof(T) +
1024  blocks.MemoryUsage();
1025 }
1026 
1027 template<typename T>
1029 {
1030  int bsize = size & mask;
1031  for (int i = blocks.Size(); i != 0; )
1032  {
1033  T *block = blocks[--i];
1034  for (int j = bsize; j != 0; )
1035  {
1036  block[--j].~T();
1037  }
1038  delete [] (char*) block;
1039  bsize = mask+1;
1040  }
1041 }
1042 
1043 } // namespace mfem
1044 
1045 #endif
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
Definition: array.hpp:310
int Size() const
Return the logical size of the array.
Definition: array.hpp:124
const_iterator(const BlockArray *a)
Definition: array.hpp:568
void Load(std::istream &in, int fmt=0)
Read an Array from the stream in using format fmt. The format fmt can be:
Definition: array.cpp:53
Array(T *_data, int asize)
Creates array using an existing c-array of asize elements; allocsize is set to -asize to indicate tha...
Definition: array.hpp:70
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T...
Definition: array.hpp:242
Memory< T > & GetMemory()
Return a reference to the Memory object used by the Array.
Definition: array.hpp:103
int NumCols() const
Definition: array.hpp:355
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition: array.hpp:278
const_iterator cbegin() const
Definition: array.hpp:580
const T * begin() const
STL-like begin. Returns const pointer to the first element of the array.
Definition: array.hpp:281
iterator_base< const BlockArray, const T > base
Definition: array.hpp:564
const T * operator()(int i) const
Definition: array.hpp:363
T * GetRow(int i)
Definition: array.hpp:367
int Capacity() const
Return the current capacity of the BlockArray.
Definition: array.hpp:486
void Load(std::istream &in, int fmt=0)
Read an Array2D from the stream in using format fmt. The format fmt can be:
Definition: array.hpp:394
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:294
int size
Size of the array.
Definition: array.hpp:50
int Size() const
Return the number of items actually stored.
Definition: array.hpp:483
void Save(std::ostream &out, int fmt=0) const
Save the Array2D to the stream out using the format fmt. The format fmt can be:
Definition: array.hpp:382
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:831
T * GetData()
Returns the data.
Definition: array.hpp:98
T * operator()(int i)
Definition: array.hpp:364
T * Write(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for write access to mem with the mfem::Device&#39;s DeviceMemoryClass, if on_dev = true...
Definition: device.hpp:324
void operator=(const T &a)
Definition: array.hpp:411
void Save(std::ostream &out, int fmt=0) const
Save the Array to the stream out using the format fmt. The format fmt can be:
Definition: array.cpp:40
bool UseDevice() const
Return the device flag of the Memory object used by the Array.
Definition: array.hpp:109
Array(int asize)
Creates array of asize elements.
Definition: array.hpp:64
void Sort(Compare cmp)
Sorts the array in ascending order using the supplied comparison function object. ...
Definition: array.hpp:238
T Sum()
Return the sum of all the array entries using the &#39;+&#39;&#39; operator for class &#39;T&#39;.
Definition: array.cpp:115
bool operator==(const iterator &other) const
Definition: array.hpp:556
void MakeRef(const Array2D &master)
Make this Array a reference to &#39;master&#39;.
Definition: array.hpp:417
iterator & operator++()
Definition: array.hpp:554
void Load(int new_size, std::istream &in)
Set the Array size to new_size and read that many entries from the stream in.
Definition: array.hpp:222
const T & At(int index) const
Definition: array.hpp:472
bool operator==(const const_iterator &other) const
Definition: array.hpp:573
void DeleteFirst(const T &el)
Delete the first entry with value == &#39;el&#39;.
Definition: array.hpp:804
T & operator[](int index)
Access item of the array.
Definition: array.hpp:479
void SetSize(int n1, int n2, int n3)
Definition: array.hpp:440
T Min() const
Find the minimal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:85
iterator(BlockArray *a)
Definition: array.hpp:551
void DeleteAll()
Delete the whole array.
Definition: array.hpp:821
int Append(const Array< T > &els)
Append another array to this array, resize if necessary.
Definition: array.hpp:158
void CopyTo(U *dest)
STL-like copyTo dest from begin to end.
Definition: array.hpp:265
iterator begin()
Definition: array.hpp:577
~Array()
Destructor.
Definition: array.hpp:82
void SetSize(int m, int n)
Definition: array.hpp:352
void Copy(Array2D &copy) const
Definition: array.hpp:408
bool OwnsData() const
Return true if the data will be deleted by the array.
Definition: array.hpp:112
const T & operator()(int i, int j) const
Definition: array.hpp:882
const T * GetData() const
Returns the data.
Definition: array.hpp:100
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:726
void DeleteAll()
Destroy all items, set size to zero.
Definition: array.hpp:489
void GetSubArray(int offset, int sa_size, Array< T > &sa) const
Copy sub array starting from offset out to the provided sa.
Definition: array.hpp:856
T & operator[](int i)
Reference access to the ith element.
Definition: array.hpp:710
double b
Definition: lissajous.cpp:42
void LoseData()
NULL-ifies the data.
Definition: array.hpp:118
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:68
long MemoryUsage() const
Definition: array.hpp:1021
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:142
void CopyFrom(const U *src)
Copy from src into this array. Copies enough entries to fill the Capacity size of this array...
Definition: array.hpp:271
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Definition: array.hpp:290
bool operator!=(const Array< T > &LHS, const Array< T > &RHS)
Definition: array.hpp:326
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition: array.hpp:275
void Assign(const T *)
Copy data from a pointer. &#39;Size()&#39; elements are copied.
Definition: array.hpp:875
long MemoryUsage() const
Returns the number of bytes allocated for the array including any reserve.
Definition: array.hpp:287
void Sort()
Sorts the array in ascending order. This requires operator&lt; to be defined for T.
Definition: array.hpp:234
int FindSorted(const T &el) const
Do bisection search for &#39;el&#39; in a sorted array; return -1 if not found.
Definition: array.hpp:795
void StealData(T **p)
Changes the ownership of the data.
Definition: array.hpp:115
const T * Read(const Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for read access to mem with the mfem::Device&#39;s DeviceMemoryClass, if on_dev = true...
Definition: device.hpp:307
int Union(const T &el)
Append element when it is not yet in the array, return index.
Definition: array.hpp:773
Dynamic 2D array using row-major layout.
Definition: array.hpp:333
Memory< T > data
Pointer to data.
Definition: array.hpp:48
void Destroy()
Definition: array.hpp:1028
void Print(std::ostream &out=mfem::out, int width=4)
Prints array to stream with width elements per row.
Definition: array.cpp:155
void Swap(Array< T > &, Array< T > &)
Definition: array.hpp:611
bool operator==(const Array< T > &LHS, const Array< T > &RHS)
Definition: array.hpp:315
void GrowSize(int minsize)
Definition: array.hpp:635
int IsSorted()
Return 1 if the array is sorted from lowest to highest. Otherwise return 0.
Definition: array.cpp:127
BlockArray(int block_size=16 *1024)
Definition: array.hpp:952
MemoryType
Memory types supported by MFEM.
Definition: mem_manager.hpp:28
int Find(const T &el) const
Return the first index where &#39;el&#39; is found; return -1 if not found.
Definition: array.hpp:785
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:654
const T * operator[](int i) const
Definition: array.hpp:902
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
Definition: array.cpp:103
T * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), on_dev).
Definition: array.hpp:306
void DeleteLast()
Delete the last entry of the array.
Definition: array.hpp:179
const T & operator[](int index) const
Definition: array.hpp:480
void MakeDataOwner() const
Make the Array own the data.
Definition: array.hpp:121
Array2D(int m, int n)
Definition: array.hpp:350
Array(MemoryType mt)
Creates an empty array with a given MemoryType.
Definition: array.hpp:61
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Definition: array.hpp:302
double a
Definition: lissajous.cpp:41
bool operator!=(const iterator &other) const
Definition: array.hpp:557
void CheckIndex(int index) const
Definition: array.hpp:590
T * ReadWrite(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for read+write access to mem with the mfem::Device&#39;s DeviceMemoryClass, if on_dev = true, or the mfem::Device&#39;s HostMemoryClass, otherwise.
Definition: device.hpp:341
Array()
Creates an empty array.
Definition: array.hpp:58
Array< T * > blocks
Definition: array.hpp:585
int Capacity() const
Definition: array.hpp:139
int index(int i, int j, int nx, int ny)
Definition: life.cpp:241
bool operator!=(const const_iterator &other) const
Definition: array.hpp:574
Class used by MFEM to store pointers to host and/or device memory.
const_iterator & operator++()
Definition: array.hpp:571
T & Last()
Return the last element in the array.
Definition: array.hpp:759
void Print(std::ostream &out=mfem::out, int width=4) const
Prints array to stream with width elements per row.
Definition: array.cpp:23
iterator_base< BlockArray, T > base
Definition: array.hpp:547
T * Write(bool on_dev=true)
Shortcut for mfem::Write(a.GetMemory(), a.Size(), on_dev).
Definition: array.hpp:298
void MakeRef(T *, int)
Make this Array a reference to a pointer.
Definition: array.hpp:839
iterator end()
Definition: array.hpp:578
Array< T > & operator=(const Array< T > &src)
Assignment operator: deep copy from &#39;src&#39;.
Definition: array.hpp:85
const_iterator cend() const
Definition: array.hpp:582
const Memory< T > & GetMemory() const
Return a reference to the Memory object used by the Array, const version.
Definition: array.hpp:106
void DeleteAll()
Delete all dynamically allocated memory, resetting all dimensions to zero.
Definition: array.hpp:421
const T & operator()(int i, int j, int k) const
Definition: array.hpp:929
Array3D(int n1, int n2, int n3)
Definition: array.hpp:437
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
const T * end() const
STL-like end. Returns const pointer after the last element of the array.
Definition: array.hpp:284
T & At(int index)
Access item of the array.
Definition: array.hpp:467
const T * GetRow(int i) const
Definition: array.hpp:366
int NumRows() const
Definition: array.hpp:354
int Prepend(const T &el)
Prepend an &#39;el&#39; to the array, resize if necessary.
Definition: array.hpp:747
int Append()
Allocate and construct a new item in the array, return its index.
Definition: array.hpp:996
void Load(int new_size0, int new_size1, std::istream &in)
Set the Array2D dimensions to new_size0 x new_size1 and read that many entries from the stream in...
Definition: array.hpp:405
void Swap(BlockArray< T > &other)
Definition: array.hpp:1012
void GetRow(int i, Array< T > &sa) const
Extract a copy of the i-th row into the Array sa.
Definition: array.hpp:370