Ginkgo: ginkgo/core/base/array.hpp Source File

| Ginkgo Generated from branch based on main. Ginkgo version 1.11.0 A numerical linear algebra library targeting many-core architectures

Loading...
Searching...
No Matches
array.hpp
1// SPDX-FileCopyrightText: 2017 - 2025 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
22namespace gko {
23
24
25template <typename ValueType>
26class array;
27
28
29namespace detail {
30
31
38template <typename SourceType, typename TargetType>
39void convert_data(std::shared_ptr<const Executor> exec, size_type size,
40 const SourceType* src, TargetType* dst);
41
42
52template <typename ValueType>
53class const_array_view {
54public:
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
134private:
135 std::shared_ptr<const Executor> exec_;
136 size_type size_;
137 const ValueType* data_;
138};
139
140
141template <typename ValueType>
142using ConstArrayView GKO_DEPRECATED("please use const_array_view") =
143 const_array_view<ValueType>;
144
145
146template <typename ValueType>
147 array<ValueType> array_const_cast(const_array_view<ValueType> view);
148
149
150} // namespace detail
151
152
165template <typename ValueType>
166 class array {
167public:
171 using value_type = ValueType;
172
176 using default_deleter = executor_deleter<value_type[]>;
177
181 using view_deleter = null_deleter<value_type[]>;
182
196 array() noexcept
197 : size_(0), data_(nullptr, default_deleter{nullptr}), exec_(nullptr)
198 {}
199
205 explicit array(std::shared_ptr<const Executor> exec) noexcept
206 : size_(0),
207 data_(nullptr, default_deleter{exec}),
208 exec_(std::move(exec))
209 {}
210
218 array(std::shared_ptr<const Executor> exec, size_type size)
219 : size_(size),
220 data_(nullptr, default_deleter{exec}),
221 exec_(std::move(exec))
222 {
223 if (size > 0) {
224 data_.reset(exec_->alloc<value_type>(size));
225 }
226 }
227
246 template <typename DeleterType>
247 array(std::shared_ptr<const Executor> exec, size_type size,
248 value_type* data, DeleterType deleter)
249 : size_{size}, data_(data, deleter), exec_{exec}
250 {}
251
262 array(std::shared_ptr<const Executor> exec, size_type size,
263 value_type* data)
264 : array(exec, size, data, default_deleter{exec})
265 {}
266
277 template <typename RandomAccessIterator>
278 array(std::shared_ptr<const Executor> exec, RandomAccessIterator begin,
279 RandomAccessIterator end)
280 : array(exec)
281 {
282 array tmp(exec->get_master(), std::distance(begin, end));
283 std::copy(begin, end, tmp.data_.get());
284 *this = std::move(tmp);
285 }
286
297 template <typename T>
298 array(std::shared_ptr<const Executor> exec,
299 std::initializer_list<T> init_list)
300 : array(exec, begin(init_list), end(init_list))
301 {}
302
312 array(std::shared_ptr<const Executor> exec, const array& other)
313 : array(exec)
314 {
315 *this = other;
316 }
317
326 array(const array& other) : array(other.get_executor(), other) {}
327
337 array(std::shared_ptr<const Executor> exec, array&& other) : array(exec)
338 {
339 *this = std::move(other);
340 }
341
350 array(array&& other) : array(other.get_executor(), std::move(other)) {}
351
365 static array view(std::shared_ptr<const Executor> exec, size_type size,
366 value_type* data)
367 {
368 return array{exec, size, data, view_deleter{}};
369 }
370
384 static detail::const_array_view<ValueType> const_view(
385 std::shared_ptr<const Executor> exec, size_type size,
386 const value_type* data)
387 {
388 return {exec, size, data};
389 }
390
395 array<ValueType> as_view()
396 {
397 return view(this->get_executor(), this->get_size(), this->get_data());
398 }
399
404 detail::const_array_view<ValueType> as_const_view() const
405 {
406 return const_view(this->get_executor(), this->get_size(),
407 this->get_const_data());
408 }
409
426 array& operator=(const array& other)
427 {
428 if (&other == this) {
429 return *this;
430 }
431 if (exec_ == nullptr) {
432 exec_ = other.get_executor();
433 data_ = data_manager{nullptr, other.data_.get_deleter()};
434 }
435 if (other.get_executor() == nullptr) {
436 this->clear();
437 return *this;
438 }
439
440 if (this->is_owning()) {
441 this->resize_and_reset(other.get_size());
442 } else {
443 GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_size(), this->get_size());
444 }
445 exec_->copy_from(other.get_executor(), other.get_size(),
446 other.get_const_data(), this->get_data());
447 return *this;
448 }
449
479 array& operator=(array&& other)
480 {
481 if (&other == this) {
482 return *this;
483 }
484 if (exec_ == nullptr) {
485 exec_ = other.get_executor();
486 data_ = data_manager{nullptr, default_deleter{exec_}};
487 }
488 if (other.get_executor() == nullptr) {
489 this->clear();
490 return *this;
491 }
492 if (exec_ == other.get_executor()) {
493 // same device, only move the pointer
494 data_ = std::exchange(
495 other.data_, data_manager{nullptr, default_deleter{exec_}});
496 size_ = std::exchange(other.size_, 0);
497 } else {
498 // different device, copy the data
499 *this = other;
500 other.clear();
501 }
502 return *this;
503 }
504
522 template <typename OtherValueType>
523 std::enable_if_t<!std::is_same<ValueType, OtherValueType>::value, array>&
524 operator=(const array<OtherValueType>& other)
525 {
526 if (this->exec_ == nullptr) {
527 this->exec_ = other.get_executor();
528 this->data_ = data_manager{nullptr, default_deleter{this->exec_}};
529 }
530 if (other.get_executor() == nullptr) {
531 this->clear();
532 return *this;
533 }
534
535 if (this->is_owning()) {
536 this->resize_and_reset(other.get_size());
537 } else {
538 GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_size(), this->get_size());
539 }
540 array<OtherValueType> tmp{this->exec_};
541 const OtherValueType* source = other.get_const_data();
542 // if we are on different executors: copy, then convert
543 if (this->exec_ != other.get_executor()) {
544 tmp = other;
545 source = tmp.get_const_data();
546 }
547 detail::convert_data(this->exec_, other.get_size(), source,
548 this->get_data());
549 return *this;
550 }
551
569 array& operator=(const detail::const_array_view<ValueType>& other)
570 {
571 if (this->exec_ == nullptr) {
572 this->exec_ = other.get_executor();
573 this->data_ = data_manager{nullptr, default_deleter{this->exec_}};
574 }
575 if (other.get_executor() == nullptr) {
576 this->clear();
577 return *this;
578 }
579
580 if (this->is_owning()) {
581 this->resize_and_reset(other.get_size());
582 } else {
583 GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_size(), this->get_size());
584 }
585 array tmp{this->exec_};
586 const ValueType* source = other.get_const_data();
587 // if we are on different executors: copy
588 if (this->exec_ != other.get_executor()) {
589 tmp = other.copy_to_array();
590 source = tmp.get_const_data();
591 }
592 exec_->copy_from(other.get_executor(), other.get_size(), source,
593 this->get_data());
594 return *this;
595 }
596
604 void clear() noexcept
605 {
606 size_ = 0;
607 data_.reset(nullptr);
608 }
609
622 void resize_and_reset(size_type size)
623 {
624 if (size == size_) {
625 return;
626 }
627 if (exec_ == nullptr) {
628 throw gko::NotSupported(__FILE__, __LINE__, __func__,
629 "gko::Executor (nullptr)");
630 }
631 if (!this->is_owning()) {
632 throw gko::NotSupported(__FILE__, __LINE__, __func__,
633 "Non owning gko::array cannot be resized.");
634 }
635
636 if (size > 0 && this->is_owning()) {
637 size_ = size;
638 data_.reset(exec_->alloc<value_type>(size));
639 } else {
640 this->clear();
641 }
642 }
643
649 std::vector<value_type> copy_to_host() const
650 {
651 std::vector<value_type> result(this->get_size());
652 auto view = make_array_view(this->get_executor()->get_master(),
653 this->get_size(), result.data());
654 view = *this;
655 return result;
656 }
657
663 void fill(const value_type value);
664
670 size_type get_size() const noexcept { return size_; }
671
677 GKO_DEPRECATED("use get_size() instead")
678 size_type get_num_elems() const noexcept { return get_size(); }
679
687 value_type* get_data() noexcept { return data_.get(); }
688
696 const value_type* get_const_data() const noexcept { return data_.get(); }
697
703 std::shared_ptr<const Executor> get_executor() const noexcept
704 {
705 return exec_;
706 }
707
714 void set_executor(std::shared_ptr<const Executor> exec)
715 {
716 if (exec == exec_) {
717 // moving to the same executor, no-op
718 return;
719 }
720 array tmp(std::move(exec));
721 tmp = *this;
722 exec_ = std::move(tmp.exec_);
723 data_ = std::move(tmp.data_);
724 }
725
737 bool is_owning()
738 {
739 return data_.get_deleter().target_type() == typeid(default_deleter);
740 }
741
742
743private:
744 // Allow other array types to access private members
745 template <typename OtherValueType>
746 friend class array;
747
748 using data_manager =
749 std::unique_ptr<value_type[], std::function<void(value_type[])>>;
750
751 size_type size_;
752 data_manager data_;
753 std::shared_ptr<const Executor> exec_;
754};
755
756
757template <typename ValueType>
758using Array GKO_DEPRECATED("please use array") = array<ValueType>;
759
760
771template <typename ValueType>
772ValueType reduce_add(const array<ValueType>& input_arr,
773 const ValueType init_val = 0);
774
785template <typename ValueType>
786 void reduce_add(const array<ValueType>& input_arr, array<ValueType>& result);
787
788
800template <typename ValueType>
801 array<ValueType> make_array_view(std::shared_ptr<const Executor> exec,
802 size_type size, ValueType* data)
803{
804 return array<ValueType>::view(exec, size, data);
805}
806
807
819template <typename ValueType>
820detail::const_array_view<ValueType> make_const_array_view(
821 std::shared_ptr<const Executor> exec, size_type size, const ValueType* data)
822{
823 return array<ValueType>::const_view(exec, size, data);
824}
825
826
827namespace detail {
828
829
830template <typename T>
831struct temporary_clone_helper<array<T>> {
832 static std::unique_ptr<array<T>> create(
833 std::shared_ptr<const Executor> exec, array<T>* ptr, bool copy_data)
834 {
835 if (copy_data) {
836 return std::make_unique<array<T>>(std::move(exec), *ptr);
837 } else {
838 return std::make_unique<array<T>>(std::move(exec), ptr->get_size());
839 }
840 }
841};
842
843template <typename T>
844struct temporary_clone_helper<const array<T>> {
845 static std::unique_ptr<const array<T>> create(
846 std::shared_ptr<const Executor> exec, const array<T>* ptr, bool)
847 {
848 return std::make_unique<const array<T>>(std::move(exec), *ptr);
849 }
850};
851
852
853// specialization for non-constant arrays, copying back via assignment
854template <typename T>
855class copy_back_deleter<array<T>>
856 : public copy_back_deleter_from_assignment<array<T>> {
857public:
858 using copy_back_deleter_from_assignment<
859 array<T>>::copy_back_deleter_from_assignment;
860};
861
862
875template <typename ValueType>
876array<ValueType> array_const_cast(const_array_view<ValueType> view)
877{
878 return array<ValueType>::view(
879 view.get_executor(), view.get_size(),
880 const_cast<ValueType*>(view.get_const_data()));
881}
882
883
884template <typename ValueType>
885array<ValueType> const_array_view<ValueType>::copy_to_array() const
886{
887 array<ValueType> result(this->get_executor(), this->get_size());
888 result.get_executor()->copy_from(this->get_executor(), this->get_size(),
889 this->get_const_data(), result.get_data());
890 return result;
891}
892
893
894} // namespace detail
895} // namespace gko
896
897
898#endif // GKO_PUBLIC_CORE_BASE_ARRAY_HPP_
gko::NotSupported
NotSupported is thrown in case it is not possible to perform the requested operation on the given obj...
Definition exception.hpp:127
gko::array
An array is a container which encapsulates fixed-sized arrays, stored on the Executor tied to the arr...
Definition array.hpp:166
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:622
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:524
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:687
gko::array::array
array(array &&other)
Moves another array.
Definition array.hpp:350
gko::array::get_executor
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor associated with the array.
Definition array.hpp:703
gko::array::operator=
array & operator=(array &&other)
Moves data from another array or view.
Definition array.hpp:479
gko::array::view_deleter
null_deleter< value_type[]> view_deleter
The deleter type used for views.
Definition array.hpp:181
gko::array::clear
void clear() noexcept
Deallocates all data used by the array.
Definition array.hpp:604
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:312
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:384
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:696
gko::array::is_owning
bool is_owning()
Tells whether this array owns its data or not.
Definition array.hpp:737
gko::array::default_deleter
executor_deleter< value_type[]> default_deleter
The default deleter type used by array.
Definition array.hpp:176
gko::array::array
array(std::shared_ptr< const Executor > exec) noexcept
Creates an empty array tied to the specified Executor.
Definition array.hpp:205
gko::array::fill
void fill(const value_type value)
Fill the array with the given value.
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:247
gko::array::as_view
array< ValueType > as_view()
Returns a non-owning view of the memory owned by this array.
Definition array.hpp:395
gko::array::value_type
ValueType value_type
The type of elements stored in the array.
Definition array.hpp:171
gko::array::get_num_elems
size_type get_num_elems() const noexcept
Returns the number of elements in the array.
Definition array.hpp:678
gko::array::array
array(std::shared_ptr< const Executor > exec, size_type size)
Creates an array on the specified Executor.
Definition array.hpp:218
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:365
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:262
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:404
gko::array::operator=
array & operator=(const array &other)
Copies data from another array or view.
Definition array.hpp:426
gko::array::array
array() noexcept
Creates an empty array not tied to any executor.
Definition array.hpp:196
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:714
gko::array::get_size
size_type get_size() const noexcept
Returns the number of elements in the array.
Definition array.hpp:670
gko::array::copy_to_host
std::vector< value_type > copy_to_host() const
Copies the data into an std::vector.
Definition array.hpp:649
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:298
gko::array::array
array(const array &other)
Creates a copy of another array.
Definition array.hpp:326
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:278
gko::array::operator=
array & operator=(const detail::const_array_view< ValueType > &other)
Copies data from a const_array_view.
Definition array.hpp:569
gko::array::array
array(std::shared_ptr< const Executor > exec, array &&other)
Moves another array to a different executor.
Definition array.hpp:337
gko::executor_deleter
This is a deleter that uses an executor's free method to deallocate the data.
Definition executor.hpp:1217
gko::null_deleter
This is a deleter that does not delete the object.
Definition utils_helper.hpp:465
gko
The Ginkgo namespace.
Definition abstract_factory.hpp:20
gko::reduce_add
ValueType reduce_add(const array< ValueType > &input_arr, const ValueType init_val=0)
Reduce (sum) the values in the array.
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:820
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:801
gko::size_type
std::size_t size_type
Integral type used for allocation quantities.
Definition types.hpp:90
gko::layout_type::array
@ array
The matrix should be written as dense matrix in column-major order.
Definition mtx_io.hpp:97
std
STL namespace.