Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_Vector.hpp
1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 // Kokkos v. 3.0
6 // Copyright (2020) National Technology & Engineering
7 // Solutions of Sandia, LLC (NTESS).
8 //
9 // Under the terms of Contract DE-NA0003525 with NTESS,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
40 //
41 // ************************************************************************
42 //@HEADER
43 */
44 
45 #ifndef KOKKOS_VECTOR_HPP
46 #define KOKKOS_VECTOR_HPP
47 
48 #include <Kokkos_Core_fwd.hpp>
49 #include <Kokkos_DualView.hpp>
50 
51 /* Drop in replacement for std::vector based on Kokkos::DualView
52  * Most functions only work on the host (it will not compile if called from
53  * device kernel)
54  *
55  */
56 namespace Kokkos {
57 
58 template <class Scalar, class Arg1Type = void>
59 class vector : public DualView<Scalar*, LayoutLeft, Arg1Type> {
60  public:
61  typedef Scalar value_type;
62  typedef Scalar* pointer;
63  typedef const Scalar* const_pointer;
64  typedef Scalar& reference;
65  typedef const Scalar& const_reference;
66  typedef Scalar* iterator;
67  typedef const Scalar* const_iterator;
68  typedef size_t size_type;
69 
70  private:
71  size_t _size;
72  float _extra_storage;
73  typedef DualView<Scalar*, LayoutLeft, Arg1Type> DV;
74 
75  public:
76 #ifdef KOKKOS_ENABLE_CUDA_UVM
77  KOKKOS_INLINE_FUNCTION reference operator()(int i) const {
78  return DV::h_view(i);
79  };
80  KOKKOS_INLINE_FUNCTION reference operator[](int i) const {
81  return DV::h_view(i);
82  };
83 #else
84  inline reference operator()(int i) const { return DV::h_view(i); };
85  inline reference operator[](int i) const { return DV::h_view(i); };
86 #endif
87 
88  /* Member functions which behave like std::vector functions */
89 
90  vector() : DV() {
91  _size = 0;
92  _extra_storage = 1.1;
93  }
94 
95  vector(int n, Scalar val = Scalar())
96  : DualView<Scalar*, LayoutLeft, Arg1Type>("Vector", size_t(n * (1.1))) {
97  _size = n;
98  _extra_storage = 1.1;
99  DV::modified_flags(0) = 1;
100 
101  assign(n, val);
102  }
103 
104  void resize(size_t n) {
105  if (n >= span()) DV::resize(size_t(n * _extra_storage));
106  _size = n;
107  }
108 
109  void resize(size_t n, const Scalar& val) { assign(n, val); }
110 
111  void assign(size_t n, const Scalar& val) {
112  /* Resize if necessary (behavior of std:vector) */
113 
114  if (n > span()) DV::resize(size_t(n * _extra_storage));
115  _size = n;
116 
117  /* Assign value either on host or on device */
118 
119  if (DV::template need_sync<typename DV::t_dev::device_type>()) {
120  set_functor_host f(DV::h_view, val);
121  parallel_for("Kokkos::vector::assign", n, f);
122  typename DV::t_host::execution_space().fence();
123  DV::template modify<typename DV::t_host::device_type>();
124  } else {
125  set_functor f(DV::d_view, val);
126  parallel_for("Kokkos::vector::assign", n, f);
127  typename DV::t_dev::execution_space().fence();
128  DV::template modify<typename DV::t_dev::device_type>();
129  }
130  }
131 
132  void reserve(size_t n) { DV::resize(size_t(n * _extra_storage)); }
133 
134  void push_back(Scalar val) {
135  DV::template sync<typename DV::t_host::device_type>();
136  DV::template modify<typename DV::t_host::device_type>();
137  if (_size == span()) {
138  size_t new_size = _size * _extra_storage;
139  if (new_size == _size) new_size++;
140  DV::resize(new_size);
141  }
142 
143  DV::h_view(_size) = val;
144  _size++;
145  }
146 
147  void pop_back() { _size--; }
148 
149  void clear() { _size = 0; }
150 
151  iterator insert(iterator it, const value_type& val) {
152  return insert(it, 1, val);
153  }
154 
155  iterator insert(iterator it, size_type count, const value_type& val) {
156  if ((size() == 0) && (it == begin())) {
157  resize(count, val);
158  DV::sync_host();
159  return begin();
160  }
161  DV::sync_host();
162  DV::modify_host();
163  if (it < begin() || it > end())
164  Kokkos::abort("Kokkos::vector::insert : invalid insert iterator");
165  if (count == 0) return it;
166  ptrdiff_t start = std::distance(begin(), it);
167  auto org_size = size();
168  resize(size() + count);
169 
170  std::copy_backward(begin() + start, begin() + org_size,
171  begin() + org_size + count);
172  std::fill_n(begin() + start, count, val);
173 
174  return begin() + start;
175  }
176 
177  private:
178  template <class T>
179  struct impl_is_input_iterator
180  : /* TODO replace this */ std::integral_constant<
181  bool, !std::is_convertible<T, size_type>::value> {};
182 
183  public:
184  // TODO: can use detection idiom to generate better error message here later
185  template <typename InputIterator>
186  typename std::enable_if<impl_is_input_iterator<InputIterator>::value,
187  iterator>::type
188  insert(iterator it, InputIterator b, InputIterator e) {
189  ptrdiff_t count = std::distance(b, e);
190  if (count == 0) return it;
191 
192  DV::sync_host();
193  DV::modify_host();
194  if (it < begin() || it > end())
195  Kokkos::abort("Kokkos::vector::insert : invalid insert iterator");
196 
197  bool resized = false;
198  if ((size() == 0) && (it == begin())) {
199  resize(count);
200  it = begin();
201  resized = true;
202  }
203  ptrdiff_t start = std::distance(begin(), it);
204  auto org_size = size();
205  if (!resized) resize(size() + count);
206  it = begin() + start;
207 
208  std::copy_backward(begin() + start, begin() + org_size,
209  begin() + org_size + count);
210  std::copy(b, e, it);
211 
212  return begin() + start;
213  }
214 
215  size_type size() const { return _size; }
216  size_type max_size() const { return 2000000000; }
217 #ifdef KOKKOS_ENABLE_DEPRECATED_CODE
218  size_type capacity() const { return DV::capacity(); }
219 #endif
220  size_type span() const { return DV::span(); }
221  bool empty() const { return _size == 0; }
222 
223  iterator begin() const { return DV::h_view.data(); }
224 
225  iterator end() const {
226  return _size > 0 ? DV::h_view.data() + _size : DV::h_view.data();
227  }
228 
229  reference front() { return DV::h_view(0); }
230 
231  reference back() { return DV::h_view(_size - 1); }
232 
233  const_reference front() const { return DV::h_view(0); }
234 
235  const_reference back() const { return DV::h_view(_size - 1); }
236 
237  /* std::algorithms which work originally with iterators, here they are
238  * implemented as member functions */
239 
240  size_t lower_bound(const size_t& start, const size_t& theEnd,
241  const Scalar& comp_val) const {
242  int lower = start; // FIXME (mfh 24 Apr 2014) narrowing conversion
243  int upper =
244  _size > theEnd
245  ? theEnd
246  : _size - 1; // FIXME (mfh 24 Apr 2014) narrowing conversion
247  if (upper <= lower) {
248  return theEnd;
249  }
250 
251  Scalar lower_val = DV::h_view(lower);
252  Scalar upper_val = DV::h_view(upper);
253  size_t idx = (upper + lower) / 2;
254  Scalar val = DV::h_view(idx);
255  if (val > upper_val) return upper;
256  if (val < lower_val) return start;
257 
258  while (upper > lower) {
259  if (comp_val > val) {
260  lower = ++idx;
261  } else {
262  upper = idx;
263  }
264  idx = (upper + lower) / 2;
265  val = DV::h_view(idx);
266  }
267  return idx;
268  }
269 
270  bool is_sorted() {
271  for (int i = 0; i < _size - 1; i++) {
272  if (DV::h_view(i) > DV::h_view(i + 1)) return false;
273  }
274  return true;
275  }
276 
277  iterator find(Scalar val) const {
278  if (_size == 0) return end();
279 
280  int upper, lower, current;
281  current = _size / 2;
282  upper = _size - 1;
283  lower = 0;
284 
285  if ((val < DV::h_view(0)) || (val > DV::h_view(_size - 1))) return end();
286 
287  while (upper > lower) {
288  if (val > DV::h_view(current))
289  lower = current + 1;
290  else
291  upper = current;
292  current = (upper + lower) / 2;
293  }
294 
295  if (val == DV::h_view(current))
296  return &DV::h_view(current);
297  else
298  return end();
299  }
300 
301  /* Additional functions for data management */
302 
303  void device_to_host() { deep_copy(DV::h_view, DV::d_view); }
304  void host_to_device() const { deep_copy(DV::d_view, DV::h_view); }
305 
306  void on_host() { DV::template modify<typename DV::t_host::device_type>(); }
307  void on_device() { DV::template modify<typename DV::t_dev::device_type>(); }
308 
309  void set_overallocation(float extra) { _extra_storage = 1.0 + extra; }
310 
311  public:
312  struct set_functor {
313  typedef typename DV::t_dev::execution_space execution_space;
314  typename DV::t_dev _data;
315  Scalar _val;
316 
317  set_functor(typename DV::t_dev data, Scalar val) : _data(data), _val(val) {}
318 
319  KOKKOS_INLINE_FUNCTION
320  void operator()(const int& i) const { _data(i) = _val; }
321  };
322 
323  struct set_functor_host {
324  typedef typename DV::t_host::execution_space execution_space;
325  typename DV::t_host _data;
326  Scalar _val;
327 
328  set_functor_host(typename DV::t_host data, Scalar val)
329  : _data(data), _val(val) {}
330 
331  KOKKOS_INLINE_FUNCTION
332  void operator()(const int& i) const { _data(i) = _val; }
333  };
334 };
335 
336 } // namespace Kokkos
337 #endif
Declaration and definition of Kokkos::DualView.
void deep_copy(const View< DT, DP...> &dst, typename ViewTraits< DT, DP...>::const_value_type &value, typename std::enable_if< std::is_same< typename ViewTraits< DT, DP...>::specialize, void >::value >::type *=nullptr)
Deep copy a value from Host memory into a view.
std::enable_if< std::is_same< typename Kokkos::View< T, P...>::array_layout, Kokkos::LayoutLeft >::value||std::is_same< typename Kokkos::View< T, P...>::array_layout, Kokkos::LayoutRight >::value >::type resize(Kokkos::View< T, P...> &v, const size_t n0=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n1=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n2=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n3=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n4=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n5=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n6=KOKKOS_IMPL_CTOR_DEFAULT_ARG, const size_t n7=KOKKOS_IMPL_CTOR_DEFAULT_ARG)
Resize a view with copying old data to new data at the corresponding indices.
void parallel_for(const ExecPolicy &policy, const FunctorType &functor, const std::string &str="", typename std::enable_if< Kokkos::Impl::is_execution_policy< ExecPolicy >::value >::type *=nullptr)
Execute functor in parallel according to the execution policy.