Ginkgo  Generated from pipelines/1330831941 branch based on master. Ginkgo version 1.8.0
A numerical linear algebra library targeting many-core architectures
array.hpp
1 // SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #ifndef GKO_PUBLIC_CORE_BASE_ARRAY_HPP_
6 #define GKO_PUBLIC_CORE_BASE_ARRAY_HPP_
7 
8 
9 #include <algorithm>
10 #include <iterator>
11 #include <memory>
12 #include <type_traits>
13 #include <utility>
14 
15 
16 #include <ginkgo/core/base/exception.hpp>
17 #include <ginkgo/core/base/exception_helpers.hpp>
18 #include <ginkgo/core/base/executor.hpp>
19 #include <ginkgo/core/base/types.hpp>
20 #include <ginkgo/core/base/utils.hpp>
21 
22 
23 namespace gko {
24 
25 
26 template <typename ValueType>
27 class array;
28 
29 
30 namespace detail {
31 
32 
39 template <typename SourceType, typename TargetType>
40 void convert_data(std::shared_ptr<const Executor> exec, size_type size,
41  const SourceType* src, TargetType* dst);
42 
43 
53 template <typename ValueType>
54 class const_array_view {
55 public:
59  using value_type = ValueType;
60 
68  const_array_view(std::shared_ptr<const Executor> exec, size_type size,
69  const ValueType* data)
70  : exec_{std::move(exec)}, size_{size}, data_{data}
71  {}
72 
73  /*
74  * To avoid any collisions with the value semantics of normal arrays,
75  * disable assignment and copy-construction altogether.
76  */
77  const_array_view& operator=(const const_array_view&) = delete;
78  const_array_view& operator=(const_array_view&&) = delete;
79  const_array_view(const const_array_view&) = delete;
80  /*
81  * TODO C++17: delete this overload as well, it is no longer necessary due
82  * to guaranteed RVO.
83  */
84  const_array_view(const_array_view&& other)
85  : const_array_view{other.exec_, other.size_, other.data_}
86  {
87  other.size_ = 0;
88  other.data_ = nullptr;
89  }
90 
96  size_type get_size() const noexcept { return size_; }
97 
103  GKO_DEPRECATED("use get_size() instead")
104  size_type get_num_elems() const noexcept { return get_size(); }
105 
111  const value_type* get_const_data() const noexcept { return data_; }
112 
118  std::shared_ptr<const Executor> get_executor() const noexcept
119  {
120  return exec_;
121  }
122 
126  bool is_owning() const noexcept { return false; }
127 
133  array<ValueType> copy_to_array() const;
134 
135 private:
136  std::shared_ptr<const Executor> exec_;
137  size_type size_;
138  const ValueType* data_;
139 };
140 
141 
142 template <typename ValueType>
143 using ConstArrayView GKO_DEPRECATED("please use const_array_view") =
144  const_array_view<ValueType>;
145 
146 
147 template <typename ValueType>
148 array<ValueType> array_const_cast(const_array_view<ValueType> view);
149 
150 
151 } // namespace detail
152 
153 
166 template <typename ValueType>
167 class array {
168 public:
172  using value_type = ValueType;
173 
178 
183 
197  array() noexcept
198  : size_(0), data_(nullptr, default_deleter{nullptr}), exec_(nullptr)
199  {}
200 
206  explicit array(std::shared_ptr<const Executor> exec) noexcept
207  : size_(0),
208  data_(nullptr, default_deleter{exec}),
209  exec_(std::move(exec))
210  {}
211 
219  array(std::shared_ptr<const Executor> exec, size_type size)
220  : size_(size),
221  data_(nullptr, default_deleter{exec}),
222  exec_(std::move(exec))
223  {
224  if (size > 0) {
225  data_.reset(exec_->alloc<value_type>(size));
226  }
227  }
228 
247  template <typename DeleterType>
248  array(std::shared_ptr<const Executor> exec, size_type size,
249  value_type* data, DeleterType deleter)
250  : size_{size}, data_(data, deleter), exec_{exec}
251  {}
252 
263  array(std::shared_ptr<const Executor> exec, size_type size,
264  value_type* data)
265  : array(exec, size, data, default_deleter{exec})
266  {}
267 
278  template <typename RandomAccessIterator>
279  array(std::shared_ptr<const Executor> exec, RandomAccessIterator begin,
280  RandomAccessIterator end)
281  : array(exec)
282  {
283  array tmp(exec->get_master(), std::distance(begin, end));
284  std::copy(begin, end, tmp.data_.get());
285  *this = std::move(tmp);
286  }
287 
298  template <typename T>
299  array(std::shared_ptr<const Executor> exec,
300  std::initializer_list<T> init_list)
301  : array(exec, begin(init_list), end(init_list))
302  {}
303 
313  array(std::shared_ptr<const Executor> exec, const array& other)
314  : array(exec)
315  {
316  *this = other;
317  }
318 
327  array(const array& other) : array(other.get_executor(), other) {}
328 
338  array(std::shared_ptr<const Executor> exec, array&& other) : array(exec)
339  {
340  *this = std::move(other);
341  }
342 
351  array(array&& other) : array(other.get_executor(), std::move(other)) {}
352 
366  static array view(std::shared_ptr<const Executor> exec, size_type size,
367  value_type* data)
368  {
369  return array{exec, size, data, view_deleter{}};
370  }
371 
385  static detail::const_array_view<ValueType> const_view(
386  std::shared_ptr<const Executor> exec, size_type size,
387  const value_type* data)
388  {
389  return {exec, size, data};
390  }
391 
397  {
398  return view(this->get_executor(), this->get_size(), this->get_data());
399  }
400 
405  detail::const_array_view<ValueType> as_const_view() const
406  {
407  return const_view(this->get_executor(), this->get_size(),
408  this->get_const_data());
409  }
410 
427  array& operator=(const array& other)
428  {
429  if (&other == this) {
430  return *this;
431  }
432  if (exec_ == nullptr) {
433  exec_ = other.get_executor();
434  data_ = data_manager{nullptr, other.data_.get_deleter()};
435  }
436  if (other.get_executor() == nullptr) {
437  this->clear();
438  return *this;
439  }
440 
441  if (this->is_owning()) {
442  this->resize_and_reset(other.get_size());
443  } else {
444  GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_size(), this->get_size());
445  }
446  exec_->copy_from(other.get_executor(), other.get_size(),
447  other.get_const_data(), this->get_data());
448  return *this;
449  }
450 
481  {
482  if (&other == this) {
483  return *this;
484  }
485  if (exec_ == nullptr) {
486  exec_ = other.get_executor();
487  data_ = data_manager{nullptr, default_deleter{exec_}};
488  }
489  if (other.get_executor() == nullptr) {
490  this->clear();
491  return *this;
492  }
493  if (exec_ == other.get_executor()) {
494  // same device, only move the pointer
495  data_ = std::exchange(
496  other.data_, data_manager{nullptr, default_deleter{exec_}});
497  size_ = std::exchange(other.size_, 0);
498  } else {
499  // different device, copy the data
500  *this = other;
501  other.clear();
502  }
503  return *this;
504  }
505 
523  template <typename OtherValueType>
524  std::enable_if_t<!std::is_same<ValueType, OtherValueType>::value, array>&
526  {
527  if (this->exec_ == nullptr) {
528  this->exec_ = other.get_executor();
529  this->data_ = data_manager{nullptr, default_deleter{this->exec_}};
530  }
531  if (other.get_executor() == nullptr) {
532  this->clear();
533  return *this;
534  }
535 
536  if (this->is_owning()) {
537  this->resize_and_reset(other.get_size());
538  } else {
539  GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_size(), this->get_size());
540  }
541  array<OtherValueType> tmp{this->exec_};
542  const OtherValueType* source = other.get_const_data();
543  // if we are on different executors: copy, then convert
544  if (this->exec_ != other.get_executor()) {
545  tmp = other;
546  source = tmp.get_const_data();
547  }
548  detail::convert_data(this->exec_, other.get_size(), source,
549  this->get_data());
550  return *this;
551  }
552 
570  array& operator=(const detail::const_array_view<ValueType>& other)
571  {
572  if (this->exec_ == nullptr) {
573  this->exec_ = other.get_executor();
574  this->data_ = data_manager{nullptr, default_deleter{this->exec_}};
575  }
576  if (other.get_executor() == nullptr) {
577  this->clear();
578  return *this;
579  }
580 
581  if (this->is_owning()) {
582  this->resize_and_reset(other.get_size());
583  } else {
584  GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_size(), this->get_size());
585  }
586  array tmp{this->exec_};
587  const ValueType* source = other.get_const_data();
588  // if we are on different executors: copy
589  if (this->exec_ != other.get_executor()) {
590  tmp = other.copy_to_array();
591  source = tmp.get_const_data();
592  }
593  exec_->copy_from(other.get_executor(), other.get_size(), source,
594  this->get_data());
595  return *this;
596  }
597 
605  void clear() noexcept
606  {
607  size_ = 0;
608  data_.reset(nullptr);
609  }
610 
624  {
625  if (size == size_) {
626  return;
627  }
628  if (exec_ == nullptr) {
629  throw gko::NotSupported(__FILE__, __LINE__, __func__,
630  "gko::Executor (nullptr)");
631  }
632  if (!this->is_owning()) {
633  throw gko::NotSupported(__FILE__, __LINE__, __func__,
634  "Non owning gko::array cannot be resized.");
635  }
636 
637  if (size > 0 && this->is_owning()) {
638  size_ = size;
639  data_.reset(exec_->alloc<value_type>(size));
640  } else {
641  this->clear();
642  }
643  }
644 
650  void fill(const value_type value);
651 
657  size_type get_size() const noexcept { return size_; }
658 
664  GKO_DEPRECATED("use get_size() instead")
665  size_type get_num_elems() const noexcept { return get_size(); }
666 
674  value_type* get_data() noexcept { return data_.get(); }
675 
683  const value_type* get_const_data() const noexcept { return data_.get(); }
684 
690  std::shared_ptr<const Executor> get_executor() const noexcept
691  {
692  return exec_;
693  }
694 
701  void set_executor(std::shared_ptr<const Executor> exec)
702  {
703  if (exec == exec_) {
704  // moving to the same executor, no-op
705  return;
706  }
707  array tmp(std::move(exec));
708  tmp = *this;
709  exec_ = std::move(tmp.exec_);
710  data_ = std::move(tmp.data_);
711  }
712 
724  bool is_owning()
725  {
726  return data_.get_deleter().target_type() == typeid(default_deleter);
727  }
728 
729 
730 private:
731  // Allow other array types to access private members
732  template <typename OtherValueType>
733  friend class array;
734 
735  using data_manager =
736  std::unique_ptr<value_type[], std::function<void(value_type[])>>;
737 
738  size_type size_;
739  data_manager data_;
740  std::shared_ptr<const Executor> exec_;
741 };
742 
743 
744 template <typename ValueType>
745 using Array GKO_DEPRECATED("please use array") = array<ValueType>;
746 
747 
758 template <typename ValueType>
759 ValueType reduce_add(const array<ValueType>& input_arr,
760  const ValueType init_val = 0);
761 
772 template <typename ValueType>
773 void reduce_add(const array<ValueType>& input_arr, array<ValueType>& result);
774 
775 
787 template <typename ValueType>
788 array<ValueType> make_array_view(std::shared_ptr<const Executor> exec,
789  size_type size, ValueType* data)
790 {
791  return array<ValueType>::view(exec, size, data);
792 }
793 
794 
806 template <typename ValueType>
807 detail::const_array_view<ValueType> make_const_array_view(
808  std::shared_ptr<const Executor> exec, size_type size, const ValueType* data)
809 {
810  return array<ValueType>::const_view(exec, size, data);
811 }
812 
813 
814 namespace detail {
815 
816 
817 template <typename T>
818 struct temporary_clone_helper<array<T>> {
819  static std::unique_ptr<array<T>> create(
820  std::shared_ptr<const Executor> exec, array<T>* ptr, bool copy_data)
821  {
822  if (copy_data) {
823  return std::make_unique<array<T>>(std::move(exec), *ptr);
824  } else {
825  return std::make_unique<array<T>>(std::move(exec), ptr->get_size());
826  }
827  }
828 };
829 
830 template <typename T>
831 struct temporary_clone_helper<const array<T>> {
832  static std::unique_ptr<const array<T>> create(
833  std::shared_ptr<const Executor> exec, const array<T>* ptr, bool)
834  {
835  return std::make_unique<const array<T>>(std::move(exec), *ptr);
836  }
837 };
838 
839 
840 // specialization for non-constant arrays, copying back via assignment
841 template <typename T>
842 class copy_back_deleter<array<T>>
843  : public copy_back_deleter_from_assignment<array<T>> {
844 public:
845  using copy_back_deleter_from_assignment<
846  array<T>>::copy_back_deleter_from_assignment;
847 };
848 
849 
862 template <typename ValueType>
863 array<ValueType> array_const_cast(const_array_view<ValueType> view)
864 {
865  return array<ValueType>::view(
866  view.get_executor(), view.get_size(),
867  const_cast<ValueType*>(view.get_const_data()));
868 }
869 
870 
871 template <typename ValueType>
872 array<ValueType> const_array_view<ValueType>::copy_to_array() const
873 {
874  array<ValueType> result(this->get_executor(), this->get_size());
875  result.get_executor()->copy_from(this->get_executor(), this->get_size(),
876  this->get_const_data(), result.get_data());
877  return result;
878 }
879 
880 
881 } // namespace detail
882 } // namespace gko
883 
884 
885 #endif // GKO_PUBLIC_CORE_BASE_ARRAY_HPP_
gko::array::array
array(const array &other)
Creates a copy of another array.
Definition: array.hpp:327
gko::array::array
array(std::shared_ptr< const Executor > exec, array &&other)
Moves another array to a different executor.
Definition: array.hpp:338
gko::array::set_executor
void set_executor(std::shared_ptr< const Executor > exec)
Changes the Executor of the array, moving the allocated data to the new Executor.
Definition: array.hpp:701
gko::executor_deleter
This is a deleter that uses an executor's free method to deallocate the data.
Definition: executor.hpp:1171
gko::array::array
array(std::shared_ptr< const Executor > exec, RandomAccessIterator begin, RandomAccessIterator end)
Creates an array on the specified Executor and initializes it with values.
Definition: array.hpp:279
gko::layout_type::array
The matrix should be written as dense matrix in column-major order.
gko::array::is_owning
bool is_owning()
Tells whether this array owns its data or not.
Definition: array.hpp:724
gko::array::view
static array view(std::shared_ptr< const Executor > exec, size_type size, value_type *data)
Creates an array from existing memory.
Definition: array.hpp:366
gko::array::operator=
array & operator=(const detail::const_array_view< ValueType > &other)
Copies data from a const_array_view.
Definition: array.hpp:570
gko::null_deleter
This is a deleter that does not delete the object.
Definition: utils_helper.hpp:467
gko::array::operator=
array & operator=(array &&other)
Moves data from another array or view.
Definition: array.hpp:480
gko::array::array
array(std::shared_ptr< const Executor > exec, size_type size)
Creates an array on the specified Executor.
Definition: array.hpp:219
gko::size_type
std::size_t size_type
Integral type used for allocation quantities.
Definition: types.hpp:108
gko::array::array
array(std::shared_ptr< const Executor > exec, size_type size, value_type *data, DeleterType deleter)
Creates an array from existing memory.
Definition: array.hpp:248
gko::make_const_array_view
detail::const_array_view< ValueType > make_const_array_view(std::shared_ptr< const Executor > exec, size_type size, const ValueType *data)
Helper function to create a const array view deducing the value type.
Definition: array.hpp:807
gko::NotSupported
NotSupported is thrown in case it is not possible to perform the requested operation on the given obj...
Definition: exception.hpp:128
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:20
gko::array::array
array(std::shared_ptr< const Executor > exec, const array &other)
Creates a copy of another array on a different executor.
Definition: array.hpp:313
gko::array
An array is a container which encapsulates fixed-sized arrays, stored on the Executor tied to the arr...
Definition: array.hpp:27
gko::array::resize_and_reset
void resize_and_reset(size_type size)
Resizes the array so it is able to hold the specified number of elements.
Definition: array.hpp:623
gko::array::as_view
array< ValueType > as_view()
Returns a non-owning view of the memory owned by this array.
Definition: array.hpp:396
gko::array::get_data
value_type * get_data() noexcept
Returns a pointer to the block of memory used to store the elements of the array.
Definition: array.hpp:674
gko::array::operator=
std::enable_if_t<!std::is_same< ValueType, OtherValueType >::value, array > & operator=(const array< OtherValueType > &other)
Copies and converts data from another array with another data type.
Definition: array.hpp:525
gko::array::array
array() noexcept
Creates an empty array not tied to any executor.
Definition: array.hpp:197
gko::array::get_executor
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor associated with the array.
Definition: array.hpp:690
gko::array::operator=
array & operator=(const array &other)
Copies data from another array or view.
Definition: array.hpp:427
gko::make_array_view
array< ValueType > make_array_view(std::shared_ptr< const Executor > exec, size_type size, ValueType *data)
Helper function to create an array view deducing the value type.
Definition: array.hpp:788
gko::array::array
array(std::shared_ptr< const Executor > exec, std::initializer_list< T > init_list)
Creates an array on the specified Executor and initializes it with values.
Definition: array.hpp:299
gko::array::array
array(std::shared_ptr< const Executor > exec) noexcept
Creates an empty array tied to the specified Executor.
Definition: array.hpp:206
gko::array::array
array(array &&other)
Moves another array.
Definition: array.hpp:351
gko::array::clear
void clear() noexcept
Deallocates all data used by the array.
Definition: array.hpp:605
gko::array::const_view
static detail::const_array_view< ValueType > const_view(std::shared_ptr< const Executor > exec, size_type size, const value_type *data)
Creates a constant (immutable) array from existing memory.
Definition: array.hpp:385
gko::array::get_const_data
const value_type * get_const_data() const noexcept
Returns a constant pointer to the block of memory used to store the elements of the array.
Definition: array.hpp:683
gko::array::as_const_view
detail::const_array_view< ValueType > as_const_view() const
Returns a non-owning constant view of the memory owned by this array.
Definition: array.hpp:405
gko::array::array
array(std::shared_ptr< const Executor > exec, size_type size, value_type *data)
Creates an array from existing memory.
Definition: array.hpp:263
gko::array::value_type
ValueType value_type
The type of elements stored in the array.
Definition: array.hpp:172
gko::array::get_size
size_type get_size() const noexcept
Returns the number of elements in the array.
Definition: array.hpp:657