Kokkos Core Kernels Package Version of the Day
Loading...
Searching...
No Matches
Kokkos_Vector.hpp
1//@HEADER
2// ************************************************************************
3//
4// Kokkos v. 4.0
5// Copyright (2022) National Technology & Engineering
6// Solutions of Sandia, LLC (NTESS).
7//
8// Under the terms of Contract DE-NA0003525 with NTESS,
9// the U.S. Government retains certain rights in this software.
10//
11// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12// See https://kokkos.org/LICENSE for license information.
13// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14//
15//@HEADER
16
17#ifndef KOKKOS_VECTOR_HPP
18#define KOKKOS_VECTOR_HPP
19#ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
20#define KOKKOS_IMPL_PUBLIC_INCLUDE
21#define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_VECTOR
22#endif
23
24#include <Kokkos_Core_fwd.hpp>
25#include <Kokkos_DualView.hpp>
26
27/* Drop in replacement for std::vector based on Kokkos::DualView
28 * Most functions only work on the host (it will not compile if called from
29 * device kernel)
30 *
31 */
32namespace Kokkos {
33
34template <class Scalar, class Arg1Type = void>
35class vector : public DualView<Scalar*, LayoutLeft, Arg1Type> {
36 public:
37 using value_type = Scalar;
38 using pointer = Scalar*;
39 using const_pointer = const Scalar*;
40 using reference = Scalar&;
41 using const_reference = const Scalar&;
42 using iterator = Scalar*;
43 using const_iterator = const Scalar*;
44 using size_type = size_t;
45
46 private:
47 size_t _size;
48 float _extra_storage;
49 using DV = DualView<Scalar*, LayoutLeft, Arg1Type>;
50
51 public:
52#ifdef KOKKOS_ENABLE_CUDA_UVM
53 KOKKOS_INLINE_FUNCTION reference operator()(int i) const {
54 return DV::h_view(i);
55 };
56 KOKKOS_INLINE_FUNCTION reference operator[](int i) const {
57 return DV::h_view(i);
58 };
59#else
60 inline reference operator()(int i) const { return DV::h_view(i); };
61 inline reference operator[](int i) const { return DV::h_view(i); };
62#endif
63
64 /* Member functions which behave like std::vector functions */
65
66 vector() : DV() {
67 _size = 0;
68 _extra_storage = 1.1;
69 }
70
71 vector(int n, Scalar val = Scalar())
72 : DualView<Scalar*, LayoutLeft, Arg1Type>("Vector", size_t(n * (1.1))) {
73 _size = n;
74 _extra_storage = 1.1;
75 DV::modified_flags(0) = 1;
76
77 assign(n, val);
78 }
79
80 void resize(size_t n) {
81 if (n >= span()) DV::resize(size_t(n * _extra_storage));
82 _size = n;
83 }
84
85 void resize(size_t n, const Scalar& val) { assign(n, val); }
86
87 void assign(size_t n, const Scalar& val) {
88 /* Resize if necessary (behavior of std:vector) */
89
90 if (n > span()) DV::resize(size_t(n * _extra_storage));
91 _size = n;
92
93 /* Assign value either on host or on device */
94
95 if (DV::template need_sync<typename DV::t_dev::device_type>()) {
96 set_functor_host f(DV::h_view, val);
97 parallel_for("Kokkos::vector::assign", n, f);
98 typename DV::t_host::execution_space().fence(
99 "Kokkos::vector::assign: fence after assigning values");
100 DV::template modify<typename DV::t_host::device_type>();
101 } else {
102 set_functor f(DV::d_view, val);
103 parallel_for("Kokkos::vector::assign", n, f);
104 typename DV::t_dev::execution_space().fence(
105 "Kokkos::vector::assign: fence after assigning values");
106 DV::template modify<typename DV::t_dev::device_type>();
107 }
108 }
109
110 void reserve(size_t n) { DV::resize(size_t(n * _extra_storage)); }
111
112 void push_back(Scalar val) {
113 DV::template sync<typename DV::t_host::device_type>();
114 DV::template modify<typename DV::t_host::device_type>();
115 if (_size == span()) {
116 size_t new_size = _size * _extra_storage;
117 if (new_size == _size) new_size++;
118 DV::resize(new_size);
119 }
120
121 DV::h_view(_size) = val;
122 _size++;
123 }
124
125 void pop_back() { _size--; }
126
127 void clear() { _size = 0; }
128
129 iterator insert(iterator it, const value_type& val) {
130 return insert(it, 1, val);
131 }
132
133 iterator insert(iterator it, size_type count, const value_type& val) {
134 if ((size() == 0) && (it == begin())) {
135 resize(count, val);
136 DV::sync_host();
137 return begin();
138 }
139 DV::sync_host();
140 DV::modify_host();
141 if (std::less<>()(it, begin()) || std::less<>()(end(), it))
142 Kokkos::abort("Kokkos::vector::insert : invalid insert iterator");
143 if (count == 0) return it;
144 ptrdiff_t start = std::distance(begin(), it);
145 auto org_size = size();
146 resize(size() + count);
147
148 std::copy_backward(begin() + start, begin() + org_size,
149 begin() + org_size + count);
150 std::fill_n(begin() + start, count, val);
151
152 return begin() + start;
153 }
154
155 private:
156 template <class T>
157 struct impl_is_input_iterator
158 : /* TODO replace this */ std::bool_constant<
159 !std::is_convertible<T, size_type>::value> {};
160
161 public:
162 // TODO: can use detection idiom to generate better error message here later
163 template <typename InputIterator>
164 std::enable_if_t<impl_is_input_iterator<InputIterator>::value, iterator>
165 insert(iterator it, InputIterator b, InputIterator e) {
166 ptrdiff_t count = std::distance(b, e);
167
168 DV::sync_host();
169 DV::modify_host();
170 if (std::less<>()(it, begin()) || std::less<>()(end(), it))
171 Kokkos::abort("Kokkos::vector::insert : invalid insert iterator");
172
173 ptrdiff_t start = std::distance(begin(), it);
174 auto org_size = size();
175
176 // Note: resize(...) invalidates it; use begin() + start instead
177 resize(size() + count);
178
179 std::copy_backward(begin() + start, begin() + org_size,
180 begin() + org_size + count);
181 std::copy(b, e, begin() + start);
182
183 return begin() + start;
184 }
185
186 KOKKOS_INLINE_FUNCTION constexpr bool is_allocated() const {
187 return DV::is_allocated();
188 }
189
190 size_type size() const { return _size; }
191 size_type max_size() const { return 2000000000; }
192 size_type span() const { return DV::span(); }
193 bool empty() const { return _size == 0; }
194
195 pointer data() const { return DV::h_view.data(); }
196
197 iterator begin() const { return DV::h_view.data(); }
198
199 const_iterator cbegin() const { return DV::h_view.data(); }
200
201 iterator end() const {
202 return _size > 0 ? DV::h_view.data() + _size : DV::h_view.data();
203 }
204
205 const_iterator cend() const {
206 return _size > 0 ? DV::h_view.data() + _size : DV::h_view.data();
207 }
208
209 reference front() { return DV::h_view(0); }
210
211 reference back() { return DV::h_view(_size - 1); }
212
213 const_reference front() const { return DV::h_view(0); }
214
215 const_reference back() const { return DV::h_view(_size - 1); }
216
217 /* std::algorithms which work originally with iterators, here they are
218 * implemented as member functions */
219
220 size_t lower_bound(const size_t& start, const size_t& theEnd,
221 const Scalar& comp_val) const {
222 int lower = start; // FIXME (mfh 24 Apr 2014) narrowing conversion
223 int upper =
224 _size > theEnd
225 ? theEnd
226 : _size - 1; // FIXME (mfh 24 Apr 2014) narrowing conversion
227 if (upper <= lower) {
228 return theEnd;
229 }
230
231 Scalar lower_val = DV::h_view(lower);
232 Scalar upper_val = DV::h_view(upper);
233 size_t idx = (upper + lower) / 2;
234 Scalar val = DV::h_view(idx);
235 if (val > upper_val) return upper;
236 if (val < lower_val) return start;
237
238 while (upper > lower) {
239 if (comp_val > val) {
240 lower = ++idx;
241 } else {
242 upper = idx;
243 }
244 idx = (upper + lower) / 2;
245 val = DV::h_view(idx);
246 }
247 return idx;
248 }
249
250 bool is_sorted() {
251 for (int i = 0; i < _size - 1; i++) {
252 if (DV::h_view(i) > DV::h_view(i + 1)) return false;
253 }
254 return true;
255 }
256
257 iterator find(Scalar val) const {
258 if (_size == 0) return end();
259
260 int upper, lower, current;
261 current = _size / 2;
262 upper = _size - 1;
263 lower = 0;
264
265 if ((val < DV::h_view(0)) || (val > DV::h_view(_size - 1))) return end();
266
267 while (upper > lower) {
268 if (val > DV::h_view(current))
269 lower = current + 1;
270 else
271 upper = current;
272 current = (upper + lower) / 2;
273 }
274
275 if (val == DV::h_view(current))
276 return &DV::h_view(current);
277 else
278 return end();
279 }
280
281 /* Additional functions for data management */
282
283 void device_to_host() { deep_copy(DV::h_view, DV::d_view); }
284 void host_to_device() const { deep_copy(DV::d_view, DV::h_view); }
285
286 void on_host() { DV::template modify<typename DV::t_host::device_type>(); }
287 void on_device() { DV::template modify<typename DV::t_dev::device_type>(); }
288
289 void set_overallocation(float extra) { _extra_storage = 1.0 + extra; }
290
291 public:
292 struct set_functor {
293 using execution_space = typename DV::t_dev::execution_space;
294 typename DV::t_dev _data;
295 Scalar _val;
296
297 set_functor(typename DV::t_dev data, Scalar val) : _data(data), _val(val) {}
298
299 KOKKOS_INLINE_FUNCTION
300 void operator()(const int& i) const { _data(i) = _val; }
301 };
302
303 struct set_functor_host {
304 using execution_space = typename DV::t_host::execution_space;
305 typename DV::t_host _data;
306 Scalar _val;
307
308 set_functor_host(typename DV::t_host data, Scalar val)
309 : _data(data), _val(val) {}
310
311 KOKKOS_INLINE_FUNCTION
312 void operator()(const int& i) const { _data(i) = _val; }
313 };
314};
315
316} // namespace Kokkos
317#ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_VECTOR
318#undef KOKKOS_IMPL_PUBLIC_INCLUDE
319#undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_VECTOR
320#endif
321#endif
Declaration and definition of Kokkos::DualView.