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 [[deprecated("since 5.7.0, use data() instead")]] 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 = data();
415 const element *end = start + m_size;
416
417 const element *rhs_start = rhs.data();
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 [[deprecated("since 5.7.0, use data() instead")]] 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
591 {
592 return m_data->shape()[0];
593 }
595 {
596 return m_data->shape()[1];
597 }
598
599protected:
600 std::shared_ptr<ArrayType> m_data;
601
602private:
603};
604
605/// \brief 1D Array
606///
607/// \ref pageNekArrays
608///
609/// Misc notes.
610///
611/// Through out the 1D Array class you will see things like "using
612/// BaseType::begin" and "using BaseType::end". This is necessary to bring the
613/// methods from the ConstArray into scope in Array class. Typically this is
614/// not necessary, but since we have method names which match those in the base
615/// class, the base class names are hidden. Therefore, we have to explicitly
616/// bring them into scope to use them.
617template <typename DataType>
618class Array<OneD, DataType> : public Array<OneD, const DataType>
619{
620public:
622 typedef typename BaseType::iterator iterator;
625 typedef typename BaseType::element element;
626
627public:
629 {
630 }
631
632 explicit Array(size_type dim1Size) : BaseType(dim1Size)
633 {
634 }
635
636 Array(size_type dim1Size, const DataType &initValue)
637 : BaseType(dim1Size, initValue)
638 {
639 }
640
641 Array(size_type dim1Size, const DataType *data) : BaseType(dim1Size, data)
642 {
643 }
644
645 Array(size_type dim1Size, DataType *data,
646 const ArrayWrapperType wrap = eArrayCopy)
647 : BaseType(dim1Size, data, wrap)
648 {
649 }
650
652 : BaseType(dim1Size, rhs)
653 {
654 }
655
657 : BaseType(dim1Size, rhs.data())
658 {
659 }
660
662 {
663 }
664
666 : BaseType(rhs.size(), rhs.data())
667 {
668 }
669
670#ifdef WITH_PYTHON
671 Array(size_type dim1Size, DataType *data, void *memory_pointer,
672 void (*python_decrement)(void *))
673 : BaseType(dim1Size, data, memory_pointer, python_decrement)
674 {
675 }
676
677 void ToPythonArray(void *memory_pointer, void (*python_decrement)(void *))
678 {
679 BaseType::ToPythonArray(memory_pointer, python_decrement);
680 }
681#endif
682
684 {
685 BaseType::operator=(rhs);
686 return *this;
687 }
688
690 const Array<OneD, DataType> &rhs, unsigned int offset)
691 {
692 Array<OneD, DataType> result(rhs);
693 result.m_offset += offset;
694 result.m_size = rhs.m_size - offset;
695 return result;
696 }
697
699 {
701 }
703 {
704 return this->m_data + this->m_offset;
705 }
706
707 using BaseType::end;
709 {
710 return this->m_data + this->m_offset + this->m_size;
711 }
712
713 using BaseType::operator[];
715 {
716 ASSERTL1(static_cast<size_type>(i) < this->size(),
717 std::string("Element ") + std::to_string(i) +
718 std::string(" requested in an array of size ") +
719 std::to_string(this->size()));
720 return (data())[i];
721 }
722
723 using BaseType::get;
724 [[deprecated("since 5.7.0, use data() instead")]] element *get()
725 {
726 return this->m_data + this->m_offset;
727 }
728
729 using BaseType::data;
731 {
732 return this->m_data + this->m_offset;
733 }
734
735 template <typename T1> friend class NekVector;
736
737 template <typename T1, typename T3> friend class NekMatrix;
738
739 friend class LinearSystem;
740
741protected:
742 void ChangeSize(size_type newSize)
743 {
744 ASSERTL1(newSize <= this->m_capacity,
745 "Can't change an array size to something larger than its "
746 "capacity.");
747 this->m_size = newSize;
748 }
749
750private:
751};
752
753/// \brief A 2D array.
754template <typename DataType>
755class Array<TwoD, DataType> : public Array<TwoD, const DataType>
756{
757public:
759 typedef typename BaseType::iterator iterator;
761 typedef typename BaseType::index index;
763 typedef typename BaseType::element element;
764
765public:
767 {
768 }
769
770 Array(size_type dim1Size, size_type dim2Size) : BaseType(dim1Size, dim2Size)
771 {
772 }
773
774 Array(size_type dim1Size, size_type dim2Size, const DataType &initValue)
775 : BaseType(dim1Size, dim2Size, initValue)
776 {
777 }
778
779 Array(size_type dim1Size, size_type dim2Size, const DataType *data)
780 : BaseType(dim1Size, dim2Size, data)
781 {
782 }
783
785 {
786 }
787
789 {
790 BaseType::operator=(rhs);
791 return *this;
792 }
793
794 using BaseType::begin;
796 {
797 return this->m_data->begin();
798 }
799
800 using BaseType::end;
802 {
803 return this->m_data->end();
804 }
805
806 using BaseType::operator[];
808 {
809 return (*this->m_data)[i];
810 }
811
812 using BaseType::get;
813 [[deprecated("since 5.7.0, use data() instead")]] element *get()
814 {
815 return this->m_data->data();
816 }
817
818 using BaseType::data;
820 {
821 return this->m_data->data();
822 }
823
824private:
825};
826
827// compare whatever
828template <typename T>
829inline bool IsEqualImpl(const T &lhs, const T &rhs, std::false_type)
830{
831 return lhs == rhs;
832}
833
834// compare floating point value
835template <typename T>
836inline bool IsEqualImpl(const T &lhs, const T &rhs, std::true_type)
837{
838 return LibUtilities::IsRealEqual(lhs, rhs);
839}
840
841template <typename T> inline bool IsEqual(const T &lhs, const T &rhs)
842{
843 return IsEqualImpl(lhs, rhs, std::is_floating_point<T>());
844}
845
846template <typename T1, typename T2>
847bool operator==(const Array<OneD, T1> &lhs, const Array<OneD, T2> &rhs)
848{
849 if (lhs.size() != rhs.size())
850 {
851 return false;
852 }
853
854 if (lhs.data() == rhs.data())
855 {
856 return true;
857 }
858
859 typename Array<OneD, T1>::size_type size_value(lhs.size());
860 for (typename Array<OneD, T1>::size_type i = 0; i < size_value; ++i)
861 {
862 if (!IsEqual(lhs[i], rhs[i]))
863 {
864 return false;
865 }
866 }
867
868 return true;
869}
870
871template <typename T1, typename T2>
872bool operator!=(const Array<OneD, T1> &lhs, const Array<OneD, T2> &rhs)
873{
874 return !(lhs == rhs);
875}
876
877template <typename DataType>
879 const Array<OneD, DataType> &lhs,
880 typename Array<OneD, DataType>::size_type offset)
881{
883}
884
885template <typename DataType>
887 typename Array<OneD, DataType>::size_type offset,
888 const Array<OneD, DataType> &rhs)
889{
891}
892
893template <typename ConstDataType, typename DataType>
896{
897 if (dest.size() != source.size())
898 {
899 dest = Array<OneD, DataType>(source.size());
900 }
901
902 std::copy(source.data(), source.data() + source.size(), dest.data());
903}
904
905template <typename ConstDataType, typename DataType>
909{
910 if (dest.size() != n)
911 {
912 dest = Array<OneD, DataType>(n);
913 }
914
915 std::copy(source.data(), source.data() + n, dest.data());
916}
917
923
924// Temporary alias for 2D nested array.
925template <class T> using TensorOfArray2D = Array<OneD, Array<OneD, T>>;
926// Temporary alias for 3D nested array. Please note that the inner arrays
927// are not const declared. It is therefore suggested to use this alias with
928// caution.
929template <class T>
931// Temporary alias for 4D nested array. Please note that the inner arrays
932// are not const declared. It is therefore suggested to use this alias with
933// caution.
934template <class T>
936// Temporary alias for 5D nested array. Please note that the inner arrays
937// are not const declared. It is therefore suggested to use this alias with
938// caution.
939template <class T>
942
943template <typename T1, typename T2>
944bool operator==(const Array<TwoD, T1> &lhs, const Array<TwoD, T2> &rhs)
945{
946 if ((lhs.GetRows() != rhs.GetRows()) ||
947 (lhs.GetColumns() != rhs.GetColumns()))
948 {
949 return false;
950 }
951
952 if (lhs.data() == rhs.data())
953 {
954 return true;
955 }
956
957 for (typename Array<OneD, T1>::size_type i = 0; i < lhs.GetRows(); ++i)
958 {
959 for (typename Array<OneD, T1>::size_type j = 0; j < lhs.GetColumns();
960 ++j)
961 {
962 if (!IsEqual(lhs[i][j], rhs[i][j]))
963 {
964 return false;
965 }
966 }
967 }
968
969 return true;
970}
971
972template <typename T1, typename T2>
973bool operator!=(const Array<TwoD, T1> &lhs, const Array<TwoD, T2> &rhs)
974{
975 return !(lhs == rhs);
976}
977
978namespace LibUtilities
979{
980static std::vector<NekDouble> NullNekDoubleVector;
981static std::vector<unsigned int> NullUnsignedIntVector;
982static std::vector<std::vector<NekDouble>> NullVectorNekDoubleVector = {
984} // namespace LibUtilities
985} // namespace Nektar
986
987#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)