Ginkgo Generated from branch based on master. Ginkgo version 1.8.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
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
23namespace gko {
24
25
26template <typename ValueType>
27class array;
28
29
30namespace detail {
31
32
39template <typename SourceType, typename TargetType>
40void convert_data(std::shared_ptr<const Executor> exec, size_type size,
41 const SourceType* src, TargetType* dst);
42
43
53template <typename ValueType>
54class const_array_view {
55public:
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
135private:
136 std::shared_ptr<const Executor> exec_;
137 size_type size_;
138 const ValueType* data_;
139};
140
141
142template <typename ValueType>
143using ConstArrayView GKO_DEPRECATED("please use const_array_view") =
144 const_array_view<ValueType>;
145
146
147template <typename ValueType>
148array<ValueType> array_const_cast(const_array_view<ValueType> view);
149
150
151} // namespace detail
152
153
166template <typename ValueType>
167class array {
168public:
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
725 {
726 return data_.get_deleter().target_type() == typeid(default_deleter);
727 }
728
729
730private:
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
744template <typename ValueType>
745using Array GKO_DEPRECATED("please use array") = array<ValueType>;
746
747
758template <typename ValueType>
759ValueType reduce_add(const array<ValueType>& input_arr,
760 const ValueType init_val = 0);
761
772template <typename ValueType>
773void reduce_add(const array<ValueType>& input_arr, array<ValueType>& result);
774
775
787template <typename ValueType>
788array<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
806template <typename ValueType>
807detail::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
814namespace detail {
815
816
817template <typename T>
818struct 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
830template <typename T>
831struct 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
841template <typename T>
842class copy_back_deleter<array<T>>
843 : public copy_back_deleter_from_assignment<array<T>> {
844public:
845 using copy_back_deleter_from_assignment<
846 array<T>>::copy_back_deleter_from_assignment;
847};
848
849
862template <typename ValueType>
863array<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
871template <typename ValueType>
872array<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_
NotSupported is thrown in case it is not possible to perform the requested operation on the given obj...
Definition exception.hpp:128
An array is a container which encapsulates fixed-sized arrays, stored on the Executor tied to the arr...
Definition logger.hpp:25
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
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
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
array(array &&other)
Moves another array.
Definition array.hpp:351
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor associated with the array.
Definition array.hpp:690
array & operator=(array &&other)
Moves data from another array or view.
Definition array.hpp:480
void clear() noexcept
Deallocates all data used by the array.
Definition array.hpp:605
array(std::shared_ptr< const Executor > exec, const array &other)
Creates a copy of another array on a different executor.
Definition array.hpp:313
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
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
bool is_owning()
Tells whether this array owns its data or not.
Definition array.hpp:724
array(std::shared_ptr< const Executor > exec) noexcept
Creates an empty array tied to the specified Executor.
Definition array.hpp:206
void fill(const value_type value)
Fill the array with the given value.
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
array< ValueType > as_view()
Returns a non-owning view of the memory owned by this array.
Definition array.hpp:396
ValueType value_type
The type of elements stored in the array.
Definition array.hpp:172
array(std::shared_ptr< const Executor > exec, size_type size)
Creates an array on the specified Executor.
Definition array.hpp:219
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
array(std::shared_ptr< const Executor > exec, size_type size, value_type *data)
Creates an array from existing memory.
Definition array.hpp:263
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
array & operator=(const array &other)
Copies data from another array or view.
Definition array.hpp:427
array() noexcept
Creates an empty array not tied to any executor.
Definition array.hpp:197
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
size_type get_size() const noexcept
Returns the number of elements in the array.
Definition array.hpp:657
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
array(const array &other)
Creates a copy of another array.
Definition array.hpp:327
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
array & operator=(const detail::const_array_view< ValueType > &other)
Copies data from a const_array_view.
Definition array.hpp:570
array(std::shared_ptr< const Executor > exec, array &&other)
Moves another array to a different executor.
Definition array.hpp:338
This is a deleter that uses an executor's free method to deallocate the data.
Definition executor.hpp:1171
This is a deleter that does not delete the object.
Definition utils_helper.hpp:467
The Ginkgo namespace.
Definition abstract_factory.hpp:20
ValueType reduce_add(const array< ValueType > &input_arr, const ValueType init_val=0)
Reduce (sum) the values in the array.
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
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
std::size_t size_type
Integral type used for allocation quantities.
Definition types.hpp:86
@ array
The matrix should be written as dense matrix in column-major order.