Nektar++
BasicUtils/SharedArray.hpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: SharedArray.hpp
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2006 Scientific Computing and Imaging Institute,
10// University of Utah (USA) and Department of Aeronautics, Imperial
11// College London (UK).
12//
13// Permission is hereby granted, free of charge, to any person obtaining a
14// copy of this software and associated documentation files (the "Software"),
15// to deal in the Software without restriction, including without limitation
16// the rights to use, copy, modify, merge, publish, distribute, sublicense,
17// and/or sell copies of the Software, and to permit persons to whom the
18// Software is furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included
21// in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29// DEALINGS IN THE SOFTWARE.
30//
31// Description:
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#ifndef NEKTAR_LIB_UTILITIES_BASIC_UTILS_SHARED_ARRAY_HPP
36#define NEKTAR_LIB_UTILITIES_BASIC_UTILS_SHARED_ARRAY_HPP
37
43
44#include <boost/multi_array.hpp>
45
46namespace Nektar
47{
48class LinearSystem;
49
51{
54};
55
56// Forward declaration for a ConstArray constructor.
57template <typename Dim, typename DataType> class Array;
58
59/// \brief 1D Array of constant elements with garbage collection and bounds
60/// checking.
61template <typename DataType> class Array<OneD, const DataType>
62{
63#ifdef WITH_PYTHON
64 struct PythonInfo
65 {
66 void *m_pyObject; // Underlying PyObject pointer
67 void (*m_callback)(void *); // Callback
68 };
69#endif
70public:
71 typedef DataType *ArrayType;
72
73 typedef const DataType &const_reference;
74 typedef DataType &reference;
75
76 typedef const DataType *const_iterator;
77 typedef DataType *iterator;
78
79 typedef DataType element;
80 typedef size_t size_type;
81
82public:
83 /// \brief Creates an empty array.
85 :
86#ifdef WITH_PYTHON
87 m_pythonInfo(nullptr),
88#endif
89 m_size(0), m_capacity(0), m_data(nullptr), m_count(nullptr),
90 m_offset(0)
91 {
92 CreateStorage(m_capacity);
93 }
94
95 /// \brief Creates an array of size dim1Size.
96 ///
97 /// If DataType is a fundamental type (double, int, etc.), then the
98 /// allocated array is uninitialized. If it is any other type, each element
99 /// is initialized with DataType's default constructor.
100 explicit Array(size_type dim1Size)
101 :
102#ifdef WITH_PYTHON
103 m_pythonInfo(nullptr),
104#endif
105 m_size(dim1Size), m_capacity(dim1Size), m_data(nullptr),
106 m_count(nullptr), m_offset(0)
107 {
108 CreateStorage(m_capacity);
110 }
111
112 /// \brief Creates a 1D array with each element
113 /// initialized to an initial value.
114 /// \param dim1Size The array's size.
115 /// \param initValue Each element's initial value.
116 ///
117 /// If DataType is a fundamental type (double, int, etc.),
118 /// then the initial value is copied directly into each
119 /// element. Otherwise, the DataType's copy constructor
120 /// is used to initialize each element.
121 Array(size_type dim1Size, const DataType &initValue)
122 :
123#ifdef WITH_PYTHON
124 m_pythonInfo(nullptr),
125#endif
126 m_size(dim1Size), m_capacity(dim1Size), m_data(nullptr),
127 m_count(nullptr), m_offset(0)
128 {
129 CreateStorage(m_capacity);
131 initValue);
132 }
133
134 /// \brief Creates a 1D array a copies data into it.
135 /// \param dim1Size the array's size.
136 /// \param data The data to copy.
137 ///
138 /// If DataType is a fundamental type (double, int, etc.), then data is
139 /// copied directly into the underlying storage. Otherwise, the DataType's
140 /// copy constructor is used to copy each element.
141 Array(size_type dim1Size, const DataType *data)
142 :
143#ifdef WITH_PYTHON
144 m_pythonInfo(nullptr),
145#endif
146 m_size(dim1Size), m_capacity(dim1Size), m_data(nullptr),
147 m_count(nullptr), m_offset(0)
148 {
149 CreateStorage(m_capacity);
151 data);
152 }
153
154 /// \brief Create a 1D array that wrap around a given pointer.
155 /// \param dim1Size The array's size.
156 /// \param data The data to wrap around.
157 /// \param wrap If true, the Array won't create new storage and copy
158 /// data. If false, it will create storage and copy data as usual.
159 Array(size_type dim1Size, DataType *data,
160 const ArrayWrapperType wrap = eArrayCopy)
161 :
162#ifdef WITH_PYTHON
163 m_pythonInfo(nullptr),
164#endif
165 m_size(dim1Size), m_capacity(dim1Size), m_data(nullptr),
166 m_count(nullptr), m_offset(0)
167 {
168 switch (wrap)
169 {
170 case eArrayCopy:
171 {
172 CreateStorage(m_capacity);
174 m_data, m_capacity, data);
175 }
176 break;
177 case eArrayWrapper:
178 {
179 m_data = data;
180 }
181 }
182 }
183
184 /// \brief Creates a 1D array that references rhs.
185 /// \param dim1Size The size of the array. This is useful
186 /// when you want this array to reference
187 /// a subset of the elements in rhs.
188 /// \param rhs Array to reference.
189 /// This constructor creates an array that references rhs.
190 /// Any changes to rhs will be reflected in this array.
191 /// The memory for the array will only be deallocated when
192 /// both rhs and this array have gone out of scope.
194 :
195#ifdef WITH_PYTHON
196 m_pythonInfo(rhs.m_pythonInfo),
197#endif
198 m_size(dim1Size), m_capacity(rhs.m_capacity), m_data(rhs.m_data),
199 m_count(rhs.m_count), m_offset(rhs.m_offset)
200 {
201 if (m_count != nullptr)
202 {
203 *m_count += 1;
204 }
205 ASSERTL0(m_size <= rhs.size(), "Requested size is \
206 larger than input array size.");
207 }
208
209#ifdef WITH_PYTHON
210 /// \brief Creates a 1D array a copies data into it.
211 /// \param dim1Size the array's size.
212 /// \param data The data to reference.
213 /// \param memory_pointer Pointer to the memory address of the array
214 /// \param python_decrement Pointer to decrementer
215 Array(size_type dim1Size, DataType *data, void *memory_pointer,
216 void (*python_decrement)(void *))
217 : m_size(dim1Size), m_capacity(dim1Size), m_data(data),
218 m_count(nullptr), m_offset(0)
219 {
220 m_count = new size_type();
221 *m_count = 1;
222
223 m_pythonInfo = new PythonInfo *();
224 *m_pythonInfo = new PythonInfo();
225 (*m_pythonInfo)->m_callback = python_decrement;
226 (*m_pythonInfo)->m_pyObject = memory_pointer;
227 }
228#endif
229
230 /// \brief Creates a reference to rhs.
232 :
233#ifdef WITH_PYTHON
234 m_pythonInfo(rhs.m_pythonInfo),
235#endif
236 m_size(rhs.m_size), m_capacity(rhs.m_capacity), m_data(rhs.m_data),
237 m_count(rhs.m_count), m_offset(rhs.m_offset)
238 {
239 if (m_count != nullptr)
240 {
241 *m_count += 1;
242 }
243 }
244
245// Disable use-after-free warning with these two functions as it appears to be
246// incorrectly triggered in GCC 12.2.
247#if __GNUC__ == 12 && __GNUC_MINOR__ == 2
248#pragma GCC diagnostic push
249#pragma GCC diagnostic ignored "-Wuse-after-free"
250#endif
252 {
253 if (m_count == nullptr)
254 {
255 return;
256 }
257
258 *m_count -= 1;
259 if (*m_count == 0)
260 {
261#ifdef WITH_PYTHON
262 if (*m_pythonInfo == nullptr)
263 {
265 MemoryManager<DataType>::RawDeallocate(m_data, m_capacity);
266 }
267 else
268 {
269 (*m_pythonInfo)->m_callback((*m_pythonInfo)->m_pyObject);
270 delete *m_pythonInfo;
271 }
272
273 delete m_pythonInfo;
274 m_pythonInfo = nullptr;
275#else
276
278 MemoryManager<DataType>::RawDeallocate(m_data, m_capacity);
279
280#endif
281
282 delete m_count; // Clean up the memory used for the reference count.
283 m_count = nullptr;
284 }
285 }
286
287 /// \brief Creates a reference to rhs.
290 {
291 if (m_count != nullptr)
292 {
293 *m_count -= 1;
294 }
295
296 if (m_count != nullptr && *m_count == 0)
297 {
298#ifdef WITH_PYTHON
299 if (*m_pythonInfo == nullptr)
300 {
302 MemoryManager<DataType>::RawDeallocate(m_data, m_capacity);
303 }
304 else if ((*rhs.m_pythonInfo) != nullptr &&
305 (*m_pythonInfo)->m_pyObject !=
306 (*rhs.m_pythonInfo)->m_pyObject)
307 {
308 (*m_pythonInfo)->m_callback((*m_pythonInfo)->m_pyObject);
309 delete *m_pythonInfo;
310 }
311
312 delete m_pythonInfo;
313 m_pythonInfo = nullptr;
314#else
315
317 MemoryManager<DataType>::RawDeallocate(m_data, m_capacity);
318#endif
319 delete m_count; // Clean up the memory used for the reference count.
320 m_count = nullptr;
321 }
322
323 m_data = rhs.m_data;
324 m_capacity = rhs.m_capacity;
325 m_count = rhs.m_count;
326 if (m_count != nullptr)
327 {
328 *m_count += 1;
329 }
330 m_offset = rhs.m_offset;
331 m_size = rhs.m_size;
332#ifdef WITH_PYTHON
333 m_pythonInfo = rhs.m_pythonInfo;
334#endif
335 return *this;
336 }
337#if __GNUC__ == 12 && __GNUC_MINOR__ == 2
338#pragma GCC diagnostic pop
339#endif
340
342 {
343 return m_data + m_offset;
344 }
346 {
347 return m_data + m_offset + m_size;
348 }
349
351 {
352 ASSERTL1(i < m_size,
353 std::string("Element ") + std::to_string(i) +
354 std::string(" requested in an array of size ") +
355 std::to_string(m_size));
356 return *(m_data + i + m_offset);
357 }
358
359 /// \brief Returns a c-style pointer to the underlying array.
360 const element *get() const
361 {
362 return m_data + m_offset;
363 }
364
365 /// \brief Returns a c-style pointer to the underlying array.
366 const element *data() const
367 {
368 return m_data + m_offset;
369 }
370
371 /// \brief Returns 1.
373 {
374 return 1;
375 }
376
377 /// \brief Returns the array's size.
379 {
380 return m_size;
381 }
382
383 /// \brief Returns the array's size.
384 /// Deprecated
385 [[deprecated("since 5.1.0, use size() instead")]] size_type num_elements()
386 const
387 {
388 WARNINGL1(false, "member function num_elements() is deprecated, "
389 "use size() instead.");
390 return m_size;
391 }
392
393 /// \brief Returns the array's capacity.
395 {
396 return m_capacity;
397 }
398
399 /// \brief Returns the array's offset.
401 {
402 return m_offset;
403 }
404
405 /// \brief Returns the array's reference counter.
407 {
408 return *m_count;
409 }
410
411 /// \brief Returns true is this array and rhs overlap.
413 {
414 const element *start = get();
415 const element *end = start + m_size;
416
417 const element *rhs_start = rhs.get();
418 const element *rhs_end = rhs_start + rhs.size();
419
420 return (rhs_start >= start && rhs_start <= end) ||
421 (rhs_end >= start && rhs_end <= end);
422 }
423
424#ifdef WITH_PYTHON
425 bool IsPythonArray()
426 {
427 return *m_pythonInfo != nullptr;
428 }
429
430 void ToPythonArray(void *memory_pointer, void (*python_decrement)(void *))
431 {
432 *m_pythonInfo = new PythonInfo();
433 (*m_pythonInfo)->m_callback = python_decrement;
434 (*m_pythonInfo)->m_pyObject = memory_pointer;
435 }
436#endif
437
438 /// \brief Creates an array with a specified offset.
439 ///
440 /// The return value will reference the same array as lhs,
441 /// but with an offset.
442 ///
443 /// For example, in the following:
444 /// \code
445 /// Array<OneD, const double> result = anArray + 10;
446 /// \endcode
447 /// result[0] == anArray[10];
448 template <typename T>
450 typename Array<OneD, T>::size_type offset);
451
452 template <typename T>
454 const Array<OneD, T> &rhs);
455
456protected:
457#ifdef WITH_PYTHON
458 PythonInfo **m_pythonInfo;
459#endif
460
463 DataType *m_data;
464
465 // m_count points to an integer used as a reference count to this array's
466 // data (m_data). Previously, the reference count was stored in the first 4
467 // bytes of the m_data array.
469
471
472private:
474 {
475 DataType *storage = MemoryManager<DataType>::RawAllocate(size);
476 m_data = storage;
477
478 // Allocate an integer to hold the reference count. Note 1, all arrays
479 // that share this array's data (ie, point to m_data) will also share
480 // the m_count data. Note 2, previously m_count pointed to "(unsigned
481 // int*)storage".
482 m_count = new size_type();
483 *m_count = 1;
484#ifdef WITH_PYTHON
485 m_pythonInfo = new PythonInfo *();
486 *m_pythonInfo = nullptr;
487#endif
488 }
489
490 template <typename T>
492 size_type offset)
493 {
494 Array<OneD, T> result(rhs);
495 result.m_offset += offset;
496 result.m_size = rhs.m_size - offset;
497 return result;
498 }
499};
500
501/// \brief 2D array with garbage collection and bounds checking.
502template <typename DataType> class Array<TwoD, const DataType>
503{
504public:
505 typedef boost::multi_array_ref<DataType, 2> ArrayType;
506
507 typedef typename ArrayType::const_reference const_reference;
508 typedef typename ArrayType::reference reference;
509
510 typedef typename ArrayType::index index;
511 typedef typename ArrayType::const_iterator const_iterator;
512 typedef typename ArrayType::iterator iterator;
513
514 typedef typename ArrayType::element element;
515 typedef typename ArrayType::size_type size_type;
516
517public:
518 Array() : m_data(CreateStorage<DataType>(0, 0))
519 {
520 }
521
522 /// \brief Constructs a 2 dimensional array. The elements of the array are
523 /// not initialized.
524 Array(size_type dim1Size, size_type dim2Size)
525 : m_data(CreateStorage<DataType>(dim1Size, dim2Size))
526 {
528 m_data->num_elements());
529 }
530
531 Array(size_type dim1Size, size_type dim2Size, const DataType &initValue)
532 : m_data(CreateStorage<DataType>(dim1Size, dim2Size))
533 {
535 m_data->data(), m_data->num_elements(), initValue);
536 }
537
538 Array(size_type dim1Size, size_type dim2Size, const DataType *data)
539 : m_data(CreateStorage<DataType>(dim1Size, dim2Size))
540 {
542 m_data->data(), m_data->num_elements(), data);
543 }
544
545 Array(const Array<TwoD, const DataType> &rhs) : m_data(rhs.m_data)
546 {
547 }
548
551 {
552 m_data = rhs.m_data;
553 return *this;
554 }
555
557 {
558 return m_data->begin();
559 }
561 {
562 return m_data->end();
563 }
565 {
566 return (*m_data)[i];
567 }
568 const element *get() const
569 {
570 return m_data->data();
571 }
572 const element *data() const
573 {
574 return m_data->data();
575 }
577 {
578 return m_data->num_dimensions();
579 }
580 const size_type *shape() const
581 {
582 return m_data->shape();
583 }
584 // m_data is a shared_ptr to a boost::multi_array_ref
586 {
587 return m_data->num_elements();
588 }
589 // deprecated interface
590 [[deprecated("since 5.1.0, use size() instead")]] size_type num_elements()
591 const
592 {
593 WARNINGL1(false, "member function num_elements() is deprecated, "
594 "use size() instead.");
595 return m_data->num_elements();
596 }
597
599 {
600 return m_data->shape()[0];
601 }
603 {
604 return m_data->shape()[1];
605 }
606
607protected:
608 std::shared_ptr<ArrayType> m_data;
609
610private:
611};
612
613/// \brief 1D Array
614///
615/// \ref pageNekArrays
616///
617/// Misc notes.
618///
619/// Through out the 1D Array class you will see things like "using
620/// BaseType::begin" and "using BaseType::end". This is necessary to bring the
621/// methods from the ConstArray into scope in Array class. Typically this is
622/// not necessary, but since we have method names which match those in the base
623/// class, the base class names are hidden. Therefore, we have to explicitly
624/// bring them into scope to use them.
625template <typename DataType>
626class Array<OneD, DataType> : public Array<OneD, const DataType>
627{
628public:
630 typedef typename BaseType::iterator iterator;
633 typedef typename BaseType::element element;
634
635public:
637 {
638 }
639
640 explicit Array(size_type dim1Size) : BaseType(dim1Size)
641 {
642 }
643
644 Array(size_type dim1Size, const DataType &initValue)
645 : BaseType(dim1Size, initValue)
646 {
647 }
648
649 Array(size_type dim1Size, const DataType *data) : BaseType(dim1Size, data)
650 {
651 }
652
653 Array(size_type dim1Size, DataType *data,
654 const ArrayWrapperType wrap = eArrayCopy)
655 : BaseType(dim1Size, data, wrap)
656 {
657 }
658
660 : BaseType(dim1Size, rhs)
661 {
662 }
663
665 : BaseType(dim1Size, rhs.data())
666 {
667 }
668
670 {
671 }
672
674 : BaseType(rhs.size(), rhs.data())
675 {
676 }
677
678#ifdef WITH_PYTHON
679 Array(size_type dim1Size, DataType *data, void *memory_pointer,
680 void (*python_decrement)(void *))
681 : BaseType(dim1Size, data, memory_pointer, python_decrement)
682 {
683 }
684
685 void ToPythonArray(void *memory_pointer, void (*python_decrement)(void *))
686 {
687 BaseType::ToPythonArray(memory_pointer, python_decrement);
688 }
689#endif
690
692 {
693 BaseType::operator=(rhs);
694 return *this;
695 }
696
698 const Array<OneD, DataType> &rhs, unsigned int offset)
699 {
700 Array<OneD, DataType> result(rhs);
701 result.m_offset += offset;
702 result.m_size = rhs.m_size - offset;
703 return result;
704 }
705
707 {
709 }
711 {
712 return this->m_data + this->m_offset;
713 }
714
715 using BaseType::end;
717 {
718 return this->m_data + this->m_offset + this->m_size;
719 }
720
721 using BaseType::operator[];
723 {
724 ASSERTL1(static_cast<size_type>(i) < this->size(),
725 std::string("Element ") + std::to_string(i) +
726 std::string(" requested in an array of size ") +
727 std::to_string(this->size()));
728 return (get())[i];
729 }
730
731 using BaseType::get;
733 {
734 return this->m_data + this->m_offset;
735 }
736
737 using BaseType::data;
739 {
740 return this->m_data + this->m_offset;
741 }
742
743 template <typename T1> friend class NekVector;
744
745 template <typename T1, typename T3> friend class NekMatrix;
746
747 friend class LinearSystem;
748
749protected:
750 void ChangeSize(size_type newSize)
751 {
752 ASSERTL1(newSize <= this->m_capacity,
753 "Can't change an array size to something larger than its "
754 "capacity.");
755 this->m_size = newSize;
756 }
757
758private:
759};
760
761/// \brief A 2D array.
762template <typename DataType>
763class Array<TwoD, DataType> : public Array<TwoD, const DataType>
764{
765public:
767 typedef typename BaseType::iterator iterator;
769 typedef typename BaseType::index index;
771 typedef typename BaseType::element element;
772
773public:
775 {
776 }
777
778 Array(size_type dim1Size, size_type dim2Size) : BaseType(dim1Size, dim2Size)
779 {
780 }
781
782 Array(size_type dim1Size, size_type dim2Size, const DataType &initValue)
783 : BaseType(dim1Size, dim2Size, initValue)
784 {
785 }
786
787 Array(size_type dim1Size, size_type dim2Size, const DataType *data)
788 : BaseType(dim1Size, dim2Size, data)
789 {
790 }
791
793 {
794 }
795
797 {
798 BaseType::operator=(rhs);
799 return *this;
800 }
801
802 using BaseType::begin;
804 {
805 return this->m_data->begin();
806 }
807
808 using BaseType::end;
810 {
811 return this->m_data->end();
812 }
813
814 using BaseType::operator[];
816 {
817 return (*this->m_data)[i];
818 }
819
820 using BaseType::get;
822 {
823 return this->m_data->data();
824 }
825
826 using BaseType::data;
828 {
829 return this->m_data->data();
830 }
831
832private:
833};
834
835// compare whatever
836template <typename T>
837inline bool IsEqualImpl(const T &lhs, const T &rhs, std::false_type)
838{
839 return lhs == rhs;
840}
841
842// compare floating point value
843template <typename T>
844inline bool IsEqualImpl(const T &lhs, const T &rhs, std::true_type)
845{
846 return LibUtilities::IsRealEqual(lhs, rhs);
847}
848
849template <typename T> inline bool IsEqual(const T &lhs, const T &rhs)
850{
851 return IsEqualImpl(lhs, rhs, std::is_floating_point<T>());
852}
853
854template <typename T1, typename T2>
855bool operator==(const Array<OneD, T1> &lhs, const Array<OneD, T2> &rhs)
856{
857 if (lhs.size() != rhs.size())
858 {
859 return false;
860 }
861
862 if (lhs.data() == rhs.data())
863 {
864 return true;
865 }
866
867 typename Array<OneD, T1>::size_type size_value(lhs.size());
868 for (typename Array<OneD, T1>::size_type i = 0; i < size_value; ++i)
869 {
870 if (!IsEqual(lhs[i], rhs[i]))
871 {
872 return false;
873 }
874 }
875
876 return true;
877}
878
879template <typename T1, typename T2>
880bool operator!=(const Array<OneD, T1> &lhs, const Array<OneD, T2> &rhs)
881{
882 return !(lhs == rhs);
883}
884
885template <typename DataType>
887 const Array<OneD, DataType> &lhs,
888 typename Array<OneD, DataType>::size_type offset)
889{
891}
892
893template <typename DataType>
895 typename Array<OneD, DataType>::size_type offset,
896 const Array<OneD, DataType> &rhs)
897{
899}
900
901template <typename ConstDataType, typename DataType>
904{
905 if (dest.size() != source.size())
906 {
907 dest = Array<OneD, DataType>(source.size());
908 }
909
910 std::copy(source.data(), source.data() + source.size(), dest.data());
911}
912
913template <typename ConstDataType, typename DataType>
917{
918 if (dest.size() != n)
919 {
920 dest = Array<OneD, DataType>(n);
921 }
922
923 std::copy(source.data(), source.data() + n, dest.data());
924}
925
931
932// Temporary alias for 2D nested array.
933template <class T> using TensorOfArray2D = Array<OneD, Array<OneD, T>>;
934// Temporary alias for 3D nested array. Please note that the inner arrays
935// are not const declared. It is therefore suggested to use this alias with
936// caution.
937template <class T>
939// Temporary alias for 4D nested array. Please note that the inner arrays
940// are not const declared. It is therefore suggested to use this alias with
941// caution.
942template <class T>
944// Temporary alias for 5D nested array. Please note that the inner arrays
945// are not const declared. It is therefore suggested to use this alias with
946// caution.
947template <class T>
950
951template <typename T1, typename T2>
952bool operator==(const Array<TwoD, T1> &lhs, const Array<TwoD, T2> &rhs)
953{
954 if ((lhs.GetRows() != rhs.GetRows()) ||
955 (lhs.GetColumns() != rhs.GetColumns()))
956 {
957 return false;
958 }
959
960 if (lhs.data() == rhs.data())
961 {
962 return true;
963 }
964
965 for (typename Array<OneD, T1>::size_type i = 0; i < lhs.GetRows(); ++i)
966 {
967 for (typename Array<OneD, T1>::size_type j = 0; j < lhs.GetColumns();
968 ++j)
969 {
970 if (!IsEqual(lhs[i][j], rhs[i][j]))
971 {
972 return false;
973 }
974 }
975 }
976
977 return true;
978}
979
980template <typename T1, typename T2>
981bool operator!=(const Array<TwoD, T1> &lhs, const Array<TwoD, T2> &rhs)
982{
983 return !(lhs == rhs);
984}
985
986namespace LibUtilities
987{
988static std::vector<NekDouble> NullNekDoubleVector;
989static std::vector<unsigned int> NullUnsignedIntVector;
990static std::vector<std::vector<NekDouble>> NullVectorNekDoubleVector = {
992} // namespace LibUtilities
993} // namespace Nektar
994
995#endif // NEKTAR_LIB_UTILITIES_BASIC_UTILS_SHARED_ARRAY_HPP
#define WARNINGL1(condition, msg)
Definition: ErrorUtil.hpp:243
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:242
Array(size_type dim1Size, const Array< OneD, DataType > &rhs)
Array(size_type dim1Size, const DataType *data)
Array(const Array< OneD, const DataType > &rhs)
static Array< OneD, DataType > CreateWithOffset(const Array< OneD, DataType > &rhs, unsigned int offset)
Array< OneD, constDataType >::const_iterator begin() const
Array(const Array< OneD, DataType > &rhs)
Array< OneD, const DataType > BaseType
Array(size_type dim1Size, DataType *data, const ArrayWrapperType wrap=eArrayCopy)
Array(size_type dim1Size, const DataType &initValue)
Array(size_type dim1Size, const Array< OneD, const DataType > &rhs)
Array< OneD, DataType > & operator=(const Array< OneD, DataType > &rhs)
1D Array of constant elements with garbage collection and bounds checking.
friend Array< OneD, T > operator+(const Array< OneD, T > &lhs, typename Array< OneD, T >::size_type offset)
Creates an array with a specified offset.
Array(size_type dim1Size, const Array< OneD, const DataType > &rhs)
Creates a 1D array that references rhs.
size_type GetCount() const
Returns the array's reference counter.
Array(size_type dim1Size, const DataType *data)
Creates a 1D array a copies data into it.
bool Overlaps(const Array< OneD, const DataType > &rhs) const
Returns true is this array and rhs overlap.
Array(size_type dim1Size)
Creates an array of size dim1Size.
Array(size_type dim1Size, DataType *data, const ArrayWrapperType wrap=eArrayCopy)
Create a 1D array that wrap around a given pointer.
size_type num_elements() const
Returns the array's size. Deprecated.
friend Array< OneD, T > operator+(typename Array< OneD, T >::size_type offset, const Array< OneD, T > &rhs)
const_reference operator[](size_type i) const
Array< OneD, const DataType > & operator=(const Array< OneD, const DataType > &rhs)
Creates a reference to rhs.
const element * get() const
Returns a c-style pointer to the underlying array.
size_type capacity() const
Returns the array's capacity.
Array(const Array< OneD, const DataType > &rhs)
Creates a reference to rhs.
size_type size() const
Returns the array's size.
static Array< OneD, T > CreateWithOffset(const Array< OneD, T > &rhs, size_type offset)
size_type GetOffset() const
Returns the array's offset.
Array(size_type dim1Size, const DataType &initValue)
Creates a 1D array with each element initialized to an initial value.
const element * data() const
Returns a c-style pointer to the underlying array.
Array(const Array< TwoD, DataType > &rhs)
Array(size_type dim1Size, size_type dim2Size, const DataType *data)
Array(size_type dim1Size, size_type dim2Size)
Array(size_type dim1Size, size_type dim2Size, const DataType &initValue)
Array< TwoD, DataType > & operator=(const Array< TwoD, DataType > &rhs)
Array< TwoD, const DataType > BaseType
2D array with garbage collection and bounds checking.
Array< TwoD, const DataType > & operator=(const Array< TwoD, const DataType > &rhs)
Array(size_type dim1Size, size_type dim2Size, const DataType &initValue)
Array(size_type dim1Size, size_type dim2Size, const DataType *data)
Array(size_type dim1Size, size_type dim2Size)
Constructs a 2 dimensional array. The elements of the array are not initialized.
boost::multi_array_ref< DataType, 2 > ArrayType
Array(const Array< TwoD, const DataType > &rhs)
const_reference operator[](index i) const
static DataType * RawAllocate(size_t NumberOfElements)
Allocates a chunk of raw, uninitialized memory, capable of holding NumberOfElements objects.
static void RawDeallocate(DataType *array, size_t NumberOfElements)
Deallocates memory allocated from RawAllocate.
def copy(self)
Definition: pycml.py:2663
static std::vector< unsigned int > NullUnsignedIntVector
static std::vector< std::vector< NekDouble > > NullVectorNekDoubleVector
static std::vector< NekDouble > NullNekDoubleVector
bool IsRealEqual(T1 &&lhs, T2 &&rhs, const unsigned int factor=NekConstants::kNekFloatCompFact)
compare reals of same type with relative tolerance
bool operator==(const Array< OneD, T1 > &lhs, const Array< OneD, T2 > &rhs)
static Array< OneD, int > NullInt1DArray
Array< OneD, DataType > operator+(const Array< OneD, DataType > &lhs, typename Array< OneD, DataType >::size_type offset)
static Array< OneD, Array< OneD, NekDouble > > NullNekDoubleArrayOfArray
bool IsEqual(const T &lhs, const T &rhs)
static Array< OneD, Array< OneD, Array< OneD, NekDouble > > > NullNekDoubleTensorOfArray3D
bool IsEqualImpl(const T &lhs, const T &rhs, std::false_type)
void CopyArrayN(const Array< OneD, ConstDataType > &source, Array< OneD, DataType > &dest, typename Array< OneD, DataType >::size_type n)
static Array< OneD, NekDouble > NullNekDouble1DArray
std::shared_ptr< boost::multi_array_ref< DataType, Dim::Value > > CreateStorage(const ExtentListType &extent)
bool operator!=(const Array< OneD, T1 > &lhs, const Array< OneD, T2 > &rhs)
void CopyArray(const Array< OneD, ConstDataType > &source, Array< OneD, DataType > &dest)