Ginkgo  Generated from pipelines/2837190956 branch based on develop. Ginkgo version 2.0.0
A numerical linear algebra library targeting many-core architectures
array.hpp
1 // SPDX-FileCopyrightText: 2017 - 2026 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 #include <ginkgo/core/base/exception.hpp>
16 #include <ginkgo/core/base/exception_helpers.hpp>
17 #include <ginkgo/core/base/executor.hpp>
18 #include <ginkgo/core/base/types.hpp>
19 #include <ginkgo/core/base/utils.hpp>
20 
21 
22 namespace gko {
23 
24 
25 template <typename ValueType>
26 class array;
27 
28 
29 namespace detail {
30 
31 
38 template <typename SourceType, typename TargetType>
39 void convert_data(std::shared_ptr<const Executor> exec, size_type size,
40  const SourceType* src, TargetType* dst);
41 
42 
52 template <typename ValueType>
53 class const_array_view {
54 public:
58  using value_type = ValueType;
59 
67  const_array_view(std::shared_ptr<const Executor> exec, size_type size,
68  const ValueType* data)
69  : exec_{std::move(exec)}, size_{size}, data_{data}
70  {}
71 
72  /*
73  * To avoid any collisions with the value semantics of normal arrays,
74  * disable assignment and copy-construction altogether.
75  */
76  const_array_view& operator=(const const_array_view&) = delete;
77  const_array_view& operator=(const_array_view&&) = delete;
78  const_array_view(const const_array_view&) = delete;
79  /*
80  * TODO C++17: delete this overload as well, it is no longer necessary due
81  * to guaranteed RVO.
82  */
83  const_array_view(const_array_view&& other)
84  : const_array_view{other.exec_, other.size_, other.data_}
85  {
86  other.size_ = 0;
87  other.data_ = nullptr;
88  }
89 
95  size_type get_size() const noexcept { return size_; }
96 
102  GKO_DEPRECATED("use get_size() instead")
103  size_type get_num_elems() const noexcept { return get_size(); }
104 
110  const value_type* get_const_data() const noexcept { return data_; }
111 
117  std::shared_ptr<const Executor> get_executor() const noexcept
118  {
119  return exec_;
120  }
121 
125  bool is_owning() const noexcept { return false; }
126 
132  array<ValueType> copy_to_array() const;
133 
134 private:
135  std::shared_ptr<const Executor> exec_;
136  size_type size_;
137  const ValueType* data_;
138 };
139 
140 
141 template <typename ValueType>
142 using ConstArrayView GKO_DEPRECATED("please use const_array_view") =
143  const_array_view<ValueType>;
144 
145 
146 template <typename ValueType>
147 array<ValueType> array_const_cast(const_array_view<ValueType> view);
148 
149 
150 } // namespace detail
151 
152 
164 template <typename ValueType>
165 class array {
166 public:
170  using value_type = ValueType;
171 
176 
181 
195  array() noexcept
196  : size_(0), data_(nullptr, default_deleter{nullptr}), exec_(nullptr)
197  {}
198 
204  explicit array(std::shared_ptr<const Executor> exec) noexcept
205  : size_(0),
206  data_(nullptr, default_deleter{exec}),
207  exec_(std::move(exec))
208  {}
209 
217  array(std::shared_ptr<const Executor> exec, size_type size)
218  : size_(size),
219  data_(nullptr, default_deleter{exec}),
220  exec_(std::move(exec))
221  {
222  if (size > 0) {
223  data_.reset(exec_->alloc<value_type>(size));
224  }
225  }
226 
245  template <typename DeleterType>
246  array(std::shared_ptr<const Executor> exec, size_type size,
247  value_type* data, DeleterType deleter)
248  : size_{size}, data_(data, deleter), exec_{exec}
249  {}
250 
261  array(std::shared_ptr<const Executor> exec, size_type size,
262  value_type* data)
263  : array(exec, size, data, default_deleter{exec})
264  {}
265 
276  template <typename RandomAccessIterator>
277  array(std::shared_ptr<const Executor> exec, RandomAccessIterator begin,
278  RandomAccessIterator end)
279  : array(exec)
280  {
281  array tmp(exec->get_master(), std::distance(begin, end));
282  std::copy(begin, end, tmp.data_.get());
283  *this = std::move(tmp);
284  }
285 
296  template <typename T>
297  array(std::shared_ptr<const Executor> exec,
298  std::initializer_list<T> init_list)
299  : array(exec, begin(init_list), end(init_list))
300  {}
301 
311  array(std::shared_ptr<const Executor> exec, const array& other)
312  : array(exec)
313  {
314  *this = other;
315  }
316 
325  array(const array& other) : array(other.get_executor(), other) {}
326 
336  array(std::shared_ptr<const Executor> exec, array&& other) : array(exec)
337  {
338  *this = std::move(other);
339  }
340 
349  array(array&& other) : array(other.get_executor(), std::move(other)) {}
350 
364  static array view(std::shared_ptr<const Executor> exec, size_type size,
365  value_type* data)
366  {
367  return array{exec, size, data, view_deleter{}};
368  }
369 
383  static detail::const_array_view<ValueType> const_view(
384  std::shared_ptr<const Executor> exec, size_type size,
385  const value_type* data)
386  {
387  return {exec, size, data};
388  }
389 
395  {
396  return view(this->get_executor(), this->get_size(), this->get_data());
397  }
398 
403  detail::const_array_view<ValueType> as_const_view() const
404  {
405  return const_view(this->get_executor(), this->get_size(),
406  this->get_const_data());
407  }
408 
425  array& operator=(const array& other)
426  {
427  if (&other == this) {
428  return *this;
429  }
430  if (exec_ == nullptr) {
431  exec_ = other.get_executor();
432  data_ = data_manager{nullptr, other.data_.get_deleter()};
433  }
434  if (other.get_executor() == nullptr) {
435  this->clear();
436  return *this;
437  }
438 
439  if (this->is_owning()) {
440  this->resize_and_reset(other.get_size());
441  } else {
442  GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_size(), this->get_size());
443  }
444  exec_->copy_from(other.get_executor(), other.get_size(),
445  other.get_const_data(), this->get_data());
446  return *this;
447  }
448 
479  {
480  if (&other == this) {
481  return *this;
482  }
483  if (exec_ == nullptr) {
484  exec_ = other.get_executor();
485  data_ = data_manager{nullptr, default_deleter{exec_}};
486  }
487  if (other.get_executor() == nullptr) {
488  this->clear();
489  return *this;
490  }
491  if (exec_ == other.get_executor()) {
492  // same device, only move the pointer
493  data_ = std::exchange(
494  other.data_, data_manager{nullptr, default_deleter{exec_}});
495  size_ = std::exchange(other.size_, 0);
496  } else {
497  // different device, copy the data
498  *this = other;
499  other.clear();
500  }
501  return *this;
502  }
503 
521  template <typename OtherValueType>
522  std::enable_if_t<!std::is_same<ValueType, OtherValueType>::value, array>&
524  {
525  if (this->exec_ == nullptr) {
526  this->exec_ = other.get_executor();
527  this->data_ = data_manager{nullptr, default_deleter{this->exec_}};
528  }
529  if (other.get_executor() == nullptr) {
530  this->clear();
531  return *this;
532  }
533 
534  if (this->is_owning()) {
535  this->resize_and_reset(other.get_size());
536  } else {
537  GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_size(), this->get_size());
538  }
539  array<OtherValueType> tmp{this->exec_};
540  const OtherValueType* source = other.get_const_data();
541  // if we are on different executors: copy, then convert
542  if (this->exec_ != other.get_executor()) {
543  tmp = other;
544  source = tmp.get_const_data();
545  }
546  detail::convert_data(this->exec_, other.get_size(), source,
547  this->get_data());
548  return *this;
549  }
550 
568  array& operator=(const detail::const_array_view<ValueType>& other)
569  {
570  if (this->exec_ == nullptr) {
571  this->exec_ = other.get_executor();
572  this->data_ = data_manager{nullptr, default_deleter{this->exec_}};
573  }
574  if (other.get_executor() == nullptr) {
575  this->clear();
576  return *this;
577  }
578 
579  if (this->is_owning()) {
580  this->resize_and_reset(other.get_size());
581  } else {
582  GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_size(), this->get_size());
583  }
584  array tmp{this->exec_};
585  const ValueType* source = other.get_const_data();
586  // if we are on different executors: copy
587  if (this->exec_ != other.get_executor()) {
588  tmp = other.copy_to_array();
589  source = tmp.get_const_data();
590  }
591  exec_->copy_from(other.get_executor(), other.get_size(), source,
592  this->get_data());
593  return *this;
594  }
595 
603  void clear() noexcept
604  {
605  size_ = 0;
606  data_.reset(nullptr);
607  }
608 
622  {
623  if (size == size_) {
624  return;
625  }
626  if (exec_ == nullptr) {
627  throw gko::NotSupported(__FILE__, __LINE__, __func__,
628  "gko::Executor (nullptr)");
629  }
630  if (!this->is_owning()) {
631  throw gko::NotSupported(__FILE__, __LINE__, __func__,
632  "Non owning gko::array cannot be resized.");
633  }
634 
635  if (size > 0 && this->is_owning()) {
636  data_.reset(exec_->alloc<value_type>(size));
637  size_ = size;
638  } else {
639  this->clear();
640  }
641  }
642 
648  std::vector<value_type> copy_to_host() const
649  {
650  std::vector<value_type> result(this->get_size());
651  auto view = make_array_view(this->get_executor()->get_master(),
652  this->get_size(), result.data());
653  view = *this;
654  return result;
655  }
656 
662  void fill(const value_type value);
663 
669  size_type get_size() const noexcept { return size_; }
670 
676  GKO_DEPRECATED("use get_size() instead")
677  size_type get_num_elems() const noexcept { return get_size(); }
678 
686  value_type* get_data() noexcept { return data_.get(); }
687 
695  const value_type* get_const_data() const noexcept { return data_.get(); }
696 
702  std::shared_ptr<const Executor> get_executor() const noexcept
703  {
704  return exec_;
705  }
706 
713  void set_executor(std::shared_ptr<const Executor> exec)
714  {
715  if (exec == exec_) {
716  // moving to the same executor, no-op
717  return;
718  }
719  array tmp(std::move(exec));
720  tmp = *this;
721  exec_ = std::move(tmp.exec_);
722  data_ = std::move(tmp.data_);
723  }
724 
736  bool is_owning()
737  {
738  return data_.get_deleter().target_type() == typeid(default_deleter);
739  }
740 
741 
742 private:
743  // Allow other array types to access private members
744  template <typename OtherValueType>
745  friend class array;
746 
747  using data_manager =
748  std::unique_ptr<value_type[], std::function<void(value_type[])>>;
749 
750  size_type size_;
751  data_manager data_;
752  std::shared_ptr<const Executor> exec_;
753 };
754 
755 
756 template <typename ValueType>
757 using Array GKO_DEPRECATED("please use array") = array<ValueType>;
758 
759 
770 template <typename ValueType>
771 ValueType reduce_add(const array<ValueType>& input_arr,
772  const ValueType init_val = 0);
773 
784 template <typename ValueType>
785 void reduce_add(const array<ValueType>& input_arr, array<ValueType>& result);
786 
787 
799 template <typename ValueType>
800 array<ValueType> make_array_view(std::shared_ptr<const Executor> exec,
801  size_type size, ValueType* data)
802 {
803  return array<ValueType>::view(exec, size, data);
804 }
805 
806 
818 template <typename ValueType>
819 detail::const_array_view<ValueType> make_const_array_view(
820  std::shared_ptr<const Executor> exec, size_type size, const ValueType* data)
821 {
822  return array<ValueType>::const_view(exec, size, data);
823 }
824 
825 
826 namespace detail {
827 
828 
829 template <typename T>
830 struct temporary_clone_helper<array<T>> {
831  static std::unique_ptr<array<T>> create(
832  std::shared_ptr<const Executor> exec, array<T>* ptr, bool copy_data)
833  {
834  if (copy_data) {
835  return std::make_unique<array<T>>(std::move(exec), *ptr);
836  } else {
837  return std::make_unique<array<T>>(std::move(exec), ptr->get_size());
838  }
839  }
840 };
841 
842 template <typename T>
843 struct temporary_clone_helper<const array<T>> {
844  static std::unique_ptr<const array<T>> create(
845  std::shared_ptr<const Executor> exec, const array<T>* ptr, bool)
846  {
847  return std::make_unique<const array<T>>(std::move(exec), *ptr);
848  }
849 };
850 
851 
852 // specialization for non-constant arrays, copying back via assignment
853 template <typename T>
854 class copy_back_deleter<array<T>>
855  : public copy_back_deleter_from_assignment<array<T>> {
856 public:
857  using copy_back_deleter_from_assignment<
858  array<T>>::copy_back_deleter_from_assignment;
859 };
860 
861 
874 template <typename ValueType>
875 array<ValueType> array_const_cast(const_array_view<ValueType> view)
876 {
877  return array<ValueType>::view(
878  view.get_executor(), view.get_size(),
879  const_cast<ValueType*>(view.get_const_data()));
880 }
881 
882 
883 template <typename ValueType>
884 array<ValueType> const_array_view<ValueType>::copy_to_array() const
885 {
886  array<ValueType> result(this->get_executor(), this->get_size());
887  result.get_executor()->copy_from(this->get_executor(), this->get_size(),
888  this->get_const_data(), result.get_data());
889  return result;
890 }
891 
892 
893 } // namespace detail
894 } // namespace gko
895 
896 
897 #endif // GKO_PUBLIC_CORE_BASE_ARRAY_HPP_
gko::array::array
array(const array &other)
Creates a copy of another array.
Definition: array.hpp:325
gko::array::array
array(std::shared_ptr< const Executor > exec, array &&other)
Moves another array to a different executor.
Definition: array.hpp:336
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:713
gko::executor_deleter
This is a deleter that uses an executor's free method to deallocate the data.
Definition: executor.hpp:1199
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:277
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:736
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:364
gko::array::operator=
array & operator=(const detail::const_array_view< ValueType > &other)
Copies data from a const_array_view.
Definition: array.hpp:568
gko::null_deleter
This is a deleter that does not delete the object.
Definition: utils_helper.hpp:497
gko::array::operator=
array & operator=(array &&other)
Moves data from another array or view.
Definition: array.hpp:478
gko::array::array
array(std::shared_ptr< const Executor > exec, size_type size)
Creates an array on the specified Executor.
Definition: array.hpp:217
gko::size_type
std::size_t size_type
Integral type used for allocation quantities.
Definition: types.hpp:101
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:246
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:819
gko::NotSupported
NotSupported is thrown in case it is not possible to perform the requested operation on the given obj...
Definition: exception.hpp:119
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:19
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:311
gko::array
An array is a container which encapsulates fixed-sized arrays, stored on the Executor tied to the arr...
Definition: array.hpp:26
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:621
gko::array::as_view
array< ValueType > as_view()
Returns a non-owning view of the memory owned by this array.
Definition: array.hpp:394
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:686
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:523
gko::array::array
array() noexcept
Creates an empty array not tied to any executor.
Definition: array.hpp:195
gko::array::get_executor
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor associated with the array.
Definition: array.hpp:702
gko::array::operator=
array & operator=(const array &other)
Copies data from another array or view.
Definition: array.hpp:425
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:800
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:297
gko::array::array
array(std::shared_ptr< const Executor > exec) noexcept
Creates an empty array tied to the specified Executor.
Definition: array.hpp:204
gko::array::array
array(array &&other)
Moves another array.
Definition: array.hpp:349
gko::array::clear
void clear() noexcept
Deallocates all data used by the array.
Definition: array.hpp:603
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:383
gko::array::copy_to_host
std::vector< value_type > copy_to_host() const
Copies the data into an std::vector.
Definition: array.hpp:648
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:695
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:403
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:261
gko::array::value_type
ValueType value_type
The type of elements stored in the array.
Definition: array.hpp:170
gko::array::get_size
size_type get_size() const noexcept
Returns the number of elements in the array.
Definition: array.hpp:669