Ginkgo Generated from branch based on master. Ginkgo version 1.7.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
array.hpp
1/*******************************<GINKGO LICENSE>******************************
2Copyright (c) 2017-2023, the Ginkgo authors
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions
7are met:
8
91. Redistributions of source code must retain the above copyright
10notice, this list of conditions and the following disclaimer.
11
122. Redistributions in binary form must reproduce the above copyright
13notice, this list of conditions and the following disclaimer in the
14documentation and/or other materials provided with the distribution.
15
163. Neither the name of the copyright holder nor the names of its
17contributors may be used to endorse or promote products derived from
18this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31******************************<GINKGO LICENSE>*******************************/
32
33#ifndef GKO_PUBLIC_CORE_BASE_ARRAY_HPP_
34#define GKO_PUBLIC_CORE_BASE_ARRAY_HPP_
35
36
37#include <algorithm>
38#include <iterator>
39#include <memory>
40#include <type_traits>
41#include <utility>
42
43
44#include <ginkgo/core/base/exception.hpp>
45#include <ginkgo/core/base/exception_helpers.hpp>
46#include <ginkgo/core/base/executor.hpp>
47#include <ginkgo/core/base/types.hpp>
48#include <ginkgo/core/base/utils.hpp>
49
50
51namespace gko {
52
53
54template <typename ValueType>
55class array;
56
57
58namespace detail {
59
60
67template <typename SourceType, typename TargetType>
68void convert_data(std::shared_ptr<const Executor> exec, size_type size,
69 const SourceType* src, TargetType* dst);
70
71
81template <typename ValueType>
82class const_array_view {
83public:
87 using value_type = ValueType;
88
96 const_array_view(std::shared_ptr<const Executor> exec, size_type num_elems,
97 const ValueType* data)
98 : exec_{std::move(exec)}, num_elems_{num_elems}, data_{data}
99 {}
100
101 /*
102 * To avoid any collisions with the value semantics of normal arrays,
103 * disable assignment and copy-construction altogether.
104 */
105 const_array_view& operator=(const const_array_view&) = delete;
106 const_array_view& operator=(const_array_view&&) = delete;
107 const_array_view(const const_array_view&) = delete;
108 /*
109 * TODO C++17: delete this overload as well, it is no longer necessary due
110 * to guaranteed RVO.
111 */
112 const_array_view(const_array_view&& other)
113 : const_array_view{other.exec_, other.num_elems_, other.data_}
114 {
115 other.num_elems_ = 0;
116 other.data_ = nullptr;
117 }
118
124 size_type get_num_elems() const noexcept { return num_elems_; }
125
131 const value_type* get_const_data() const noexcept { return data_; }
132
138 std::shared_ptr<const Executor> get_executor() const noexcept
139 {
140 return exec_;
141 }
142
146 bool is_owning() const noexcept { return false; }
147
153 array<ValueType> copy_to_array() const;
154
155private:
156 std::shared_ptr<const Executor> exec_;
157 size_type num_elems_;
158 const ValueType* data_;
159};
160
161
162template <typename ValueType>
163using ConstArrayView GKO_DEPRECATED("please use const_array_view") =
164 const_array_view<ValueType>;
165
166
167template <typename ValueType>
168array<ValueType> array_const_cast(const_array_view<ValueType> view);
169
170
171} // namespace detail
172
173
186template <typename ValueType>
187class array {
188public:
192 using value_type = ValueType;
193
198
203
218 : num_elems_(0),
219 data_(nullptr, default_deleter{nullptr}),
220 exec_(nullptr)
221 {}
222
228 explicit array(std::shared_ptr<const Executor> exec) noexcept
229 : num_elems_(0),
230 data_(nullptr, default_deleter{exec}),
231 exec_(std::move(exec))
232 {}
233
241 array(std::shared_ptr<const Executor> exec, size_type num_elems)
242 : num_elems_(num_elems),
243 data_(nullptr, default_deleter{exec}),
244 exec_(std::move(exec))
245 {
246 if (num_elems > 0) {
247 data_.reset(exec_->alloc<value_type>(num_elems));
248 }
249 }
250
269 template <typename DeleterType>
270 array(std::shared_ptr<const Executor> exec, size_type num_elems,
272 : num_elems_{num_elems}, data_(data, deleter), exec_{exec}
273 {}
274
285 array(std::shared_ptr<const Executor> exec, size_type num_elems,
286 value_type* data)
287 : array(exec, num_elems, data, default_deleter{exec})
288 {}
289
300 template <typename RandomAccessIterator>
301 array(std::shared_ptr<const Executor> exec, RandomAccessIterator begin,
303 : array(exec)
304 {
305 array tmp(exec->get_master(), std::distance(begin, end));
306 std::copy(begin, end, tmp.data_.get());
307 *this = std::move(tmp);
308 }
309
320 template <typename T>
321 array(std::shared_ptr<const Executor> exec,
322 std::initializer_list<T> init_list)
323 : array(exec, begin(init_list), end(init_list))
324 {}
325
335 array(std::shared_ptr<const Executor> exec, const array& other)
336 : array(exec)
337 {
338 *this = other;
339 }
340
350
360 array(std::shared_ptr<const Executor> exec, array&& other) : array(exec)
361 {
362 *this = std::move(other);
363 }
364
374
388 static array view(std::shared_ptr<const Executor> exec, size_type num_elems,
389 value_type* data)
390 {
391 return array{exec, num_elems, data, view_deleter{}};
392 }
393
407 static detail::const_array_view<ValueType> const_view(
408 std::shared_ptr<const Executor> exec, size_type num_elems,
409 const value_type* data)
410 {
411 return {exec, num_elems, data};
412 }
413
419 {
420 return view(this->get_executor(), this->get_num_elems(),
421 this->get_data());
422 }
423
428 detail::const_array_view<ValueType> as_const_view() const
429 {
430 return const_view(this->get_executor(), this->get_num_elems(),
431 this->get_const_data());
432 }
433
451 {
452 if (&other == this) {
453 return *this;
454 }
455 if (exec_ == nullptr) {
456 exec_ = other.get_executor();
457 data_ = data_manager{nullptr, other.data_.get_deleter()};
458 }
459 if (other.get_executor() == nullptr) {
460 this->clear();
461 return *this;
462 }
463
464 if (this->is_owning()) {
465 this->resize_and_reset(other.get_num_elems());
466 } else {
467 GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_num_elems(),
468 this->num_elems_);
469 }
470 exec_->copy_from(other.get_executor(), other.get_num_elems(),
471 other.get_const_data(), this->get_data());
472 return *this;
473 }
474
505 {
506 if (&other == this) {
507 return *this;
508 }
509 if (exec_ == nullptr) {
510 exec_ = other.get_executor();
511 data_ = data_manager{nullptr, default_deleter{exec_}};
512 }
513 if (other.get_executor() == nullptr) {
514 this->clear();
515 return *this;
516 }
517 if (exec_ == other.get_executor()) {
518 // same device, only move the pointer
519 data_ = std::exchange(
520 other.data_, data_manager{nullptr, default_deleter{exec_}});
521 num_elems_ = std::exchange(other.num_elems_, 0);
522 } else {
523 // different device, copy the data
524 *this = other;
525 other.clear();
526 }
527 return *this;
528 }
529
547 template <typename OtherValueType>
548 std::enable_if_t<!std::is_same<ValueType, OtherValueType>::value, array>&
550 {
551 if (this->exec_ == nullptr) {
552 this->exec_ = other.get_executor();
553 this->data_ = data_manager{nullptr, default_deleter{this->exec_}};
554 }
555 if (other.get_executor() == nullptr) {
556 this->clear();
557 return *this;
558 }
559
560 if (this->is_owning()) {
561 this->resize_and_reset(other.get_num_elems());
562 } else {
563 GKO_ENSURE_COMPATIBLE_BOUNDS(other.get_num_elems(),
564 this->num_elems_);
565 }
566 array<OtherValueType> tmp{this->exec_};
568 // if we are on different executors: copy, then convert
569 if (this->exec_ != other.get_executor()) {
570 tmp = other;
571 source = tmp.get_const_data();
572 }
573 detail::convert_data(this->exec_, other.get_num_elems(), source,
574 this->get_data());
575 return *this;
576 }
577
586 {
587 num_elems_ = 0;
588 data_.reset(nullptr);
589 }
590
604 {
605 if (num_elems == num_elems_) {
606 return;
607 }
608 if (exec_ == nullptr) {
610 "gko::Executor (nullptr)");
611 }
612 if (!this->is_owning()) {
614 "Non owning gko::array cannot be resized.");
615 }
616
617 if (num_elems > 0 && this->is_owning()) {
618 num_elems_ = num_elems;
619 data_.reset(exec_->alloc<value_type>(num_elems));
620 } else {
621 this->clear();
622 }
623 }
624
630 void fill(const value_type value);
631
637 size_type get_num_elems() const noexcept { return num_elems_; }
638
646 value_type* get_data() noexcept { return data_.get(); }
647
655 const value_type* get_const_data() const noexcept { return data_.get(); }
656
662 std::shared_ptr<const Executor> get_executor() const noexcept
663 {
664 return exec_;
665 }
666
673 void set_executor(std::shared_ptr<const Executor> exec)
674 {
675 if (exec == exec_) {
676 // moving to the same executor, no-op
677 return;
678 }
679 array tmp(std::move(exec));
680 tmp = *this;
681 exec_ = std::move(tmp.exec_);
682 data_ = std::move(tmp.data_);
683 }
684
697 {
698 return data_.get_deleter().target_type() == typeid(default_deleter);
699 }
700
701
702private:
703 // Allow other array types to access private members
704 template <typename OtherValueType>
705 friend class array;
706
707 using data_manager =
708 std::unique_ptr<value_type[], std::function<void(value_type[])>>;
709
710 size_type num_elems_;
711 data_manager data_;
712 std::shared_ptr<const Executor> exec_;
713};
714
715
716template <typename ValueType>
717using Array GKO_DEPRECATED("please use array") = array<ValueType>;
718
719
730template <typename ValueType>
731ValueType reduce_add(const array<ValueType>& input_arr,
732 const ValueType init_val = 0);
733
744template <typename ValueType>
745void reduce_add(const array<ValueType>& input_arr, array<ValueType>& result);
746
747
759template <typename ValueType>
760array<ValueType> make_array_view(std::shared_ptr<const Executor> exec,
761 size_type size, ValueType* data)
762{
763 return array<ValueType>::view(exec, size, data);
764}
765
766
778template <typename ValueType>
779detail::const_array_view<ValueType> make_const_array_view(
780 std::shared_ptr<const Executor> exec, size_type size, const ValueType* data)
781{
782 return array<ValueType>::const_view(exec, size, data);
783}
784
785
786namespace detail {
787
788
789template <typename T>
790struct temporary_clone_helper<array<T>> {
791 static std::unique_ptr<array<T>> create(
792 std::shared_ptr<const Executor> exec, array<T>* ptr, bool copy_data)
793 {
794 if (copy_data) {
795 return std::make_unique<array<T>>(std::move(exec), *ptr);
796 } else {
797 return std::make_unique<array<T>>(std::move(exec),
798 ptr->get_num_elems());
799 }
800 }
801};
802
803template <typename T>
804struct temporary_clone_helper<const array<T>> {
805 static std::unique_ptr<const array<T>> create(
806 std::shared_ptr<const Executor> exec, const array<T>* ptr, bool)
807 {
808 return std::make_unique<const array<T>>(std::move(exec), *ptr);
809 }
810};
811
812
813// specialization for non-constant arrays, copying back via assignment
814template <typename T>
815class copy_back_deleter<array<T>> {
816public:
817 using pointer = array<T>*;
818
825 copy_back_deleter(pointer original) : original_{original} {}
826
832 void operator()(pointer ptr) const
833 {
834 *original_ = *ptr;
835 delete ptr;
836 }
837
838private:
839 pointer original_;
840};
841
842
855template <typename ValueType>
856array<ValueType> array_const_cast(const_array_view<ValueType> view)
857{
858 return array<ValueType>::view(
859 view.get_executor(), view.get_num_elems(),
860 const_cast<ValueType*>(view.get_const_data()));
861}
862
863
864template <typename ValueType>
865array<ValueType> const_array_view<ValueType>::copy_to_array() const
866{
867 array<ValueType> result(this->get_executor(), this->get_num_elems());
868 result.get_executor()->copy_from(this->get_executor(),
869 this->get_num_elems(),
870 this->get_const_data(), result.get_data());
871 return result;
872}
873
874
875} // namespace detail
876} // namespace gko
877
878
879#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:156
An array is a container which encapsulates fixed-sized arrays, stored on the Executor tied to the arr...
Definition array.hpp:187
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:549
value_type * get_data() noexcept
Returns a pointer to the block of memory used to store the elements of the array.
Definition array.hpp:646
array(array &&other)
Moves another array.
Definition array.hpp:373
std::shared_ptr< const Executor > get_executor() const noexcept
Returns the Executor associated with the array.
Definition array.hpp:662
array & operator=(array &&other)
Moves data from another array or view.
Definition array.hpp:504
void clear() noexcept
Deallocates all data used by the array.
Definition array.hpp:585
static detail::const_array_view< ValueType > const_view(std::shared_ptr< const Executor > exec, size_type num_elems, const value_type *data)
Creates a constant (immutable) array from existing memory.
Definition array.hpp:407
array(std::shared_ptr< const Executor > exec, size_type num_elems)
Creates an array on the specified Executor.
Definition array.hpp:241
array(std::shared_ptr< const Executor > exec, const array &other)
Creates a copy of another array on a different executor.
Definition array.hpp:335
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:655
bool is_owning()
Tells whether this array owns its data or not.
Definition array.hpp:696
array(std::shared_ptr< const Executor > exec) noexcept
Creates an empty array tied to the specified Executor.
Definition array.hpp:228
void resize_and_reset(size_type num_elems)
Resizes the array so it is able to hold the specified number of elements.
Definition array.hpp:603
void fill(const value_type value)
Fill the array with the given value.
array< ValueType > as_view()
Returns a non-owning view of the memory owned by this array.
Definition array.hpp:418
ValueType value_type
The type of elements stored in the array.
Definition array.hpp:192
size_type get_num_elems() const noexcept
Returns the number of elements in the array.
Definition array.hpp:637
static array view(std::shared_ptr< const Executor > exec, size_type num_elems, value_type *data)
Creates an array from existing memory.
Definition array.hpp:388
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:428
array & operator=(const array &other)
Copies data from another array or view.
Definition array.hpp:450
array() noexcept
Creates an empty array not tied to any executor.
Definition array.hpp:217
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:673
array(std::shared_ptr< const Executor > exec, size_type num_elems, value_type *data)
Creates an array from existing memory.
Definition array.hpp:285
array(std::shared_ptr< const Executor > exec, size_type num_elems, value_type *data, DeleterType deleter)
Creates an array from existing memory.
Definition array.hpp:270
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:321
array(const array &other)
Creates a copy of another array.
Definition array.hpp:349
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:301
array(std::shared_ptr< const Executor > exec, array &&other)
Moves another array to a different executor.
Definition array.hpp:360
This is a deleter that uses an executor's free method to deallocate the data.
Definition executor.hpp:1199
This is a deleter that does not delete the object.
Definition utils_helper.hpp:495
The Ginkgo namespace.
Definition abstract_factory.hpp:48
constexpr T one()
Returns the multiplicative identity for T.
Definition math.hpp:803
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:779
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:760
std::size_t size_type
Integral type used for allocation quantities.
Definition types.hpp:120
@ array
The matrix should be written as dense matrix in column-major order.