RAJA
RAJA provides a collection of platform portability abstractions for C++ HPC applications.
RAJAVec.hpp
Go to the documentation of this file.
1 
12 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
13 // Copyright (c) Lawrence Livermore National Security, LLC and other
14 // RAJA Project Developers. See top-level LICENSE and COPYRIGHT
15 // files for dates and other details. No copyright assignment is required
16 // to contribute to RAJA.
17 //
18 // SPDX-License-Identifier: (BSD-3-Clause)
19 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
20 
21 #ifndef RAJAVec_HPP
22 #define RAJAVec_HPP
23 
24 #include "RAJA/config.hpp"
25 
26 #include <algorithm>
27 #include <cstddef>
28 #include <memory>
29 #include <utility>
30 
32 
33 namespace RAJA
34 {
35 
54 template<typename T, typename Allocator = std::allocator<T>>
55 class RAJAVec
56 {
57  using allocator_traits_type = std::allocator_traits<Allocator>;
58  using propagate_on_container_copy_assignment =
59  typename allocator_traits_type::propagate_on_container_copy_assignment;
60  using propagate_on_container_move_assignment =
61  typename allocator_traits_type::propagate_on_container_move_assignment;
62  using propagate_on_container_swap =
63  typename allocator_traits_type::propagate_on_container_swap;
64 
65 public:
66  using value_type = T;
67  using allocator_type = Allocator;
68  using size_type = std::size_t;
69  using difference_type = std::ptrdiff_t;
71  using const_reference = const value_type&;
72  using pointer = typename allocator_traits_type::pointer;
73  using const_pointer = typename allocator_traits_type::const_pointer;
74  using iterator = value_type*;
75  using const_iterator = const value_type*;
76 
80  explicit RAJAVec(size_type init_cap = 0,
81  const allocator_type& a = allocator_type())
82  : m_data(nullptr),
83  m_allocator(a),
84  m_capacity(0),
85  m_size(0)
86  {
87  reserve(init_cap);
88  }
89 
93  RAJAVec(const RAJAVec& other)
94  : m_data(nullptr),
95  m_allocator(
96  allocator_traits_type::select_on_container_copy_construction(
97  other.m_allocator)),
98  m_capacity(0),
99  m_size(0)
100  {
101  reserve(other.size());
102  copy_construct_items_back(other.size(), other.data());
103  }
104 
108  RAJAVec(RAJAVec&& other)
109  : m_data(other.m_data),
110  m_allocator(std::move(other.m_allocator)),
111  m_capacity(other.m_capacity),
112  m_size(other.m_size)
113  {
114  other.m_data = nullptr;
115  other.m_capacity = 0;
116  other.m_size = 0;
117  }
118 
122  RAJAVec& operator=(const RAJAVec& rhs)
123  {
124  if (&rhs != this)
125  {
126  copy_assign_private(rhs, propagate_on_container_copy_assignment {});
127  }
128  return *this;
129  }
130 
135  {
136  if (&rhs != this)
137  {
138  move_assign_private(std::move(rhs),
139  propagate_on_container_move_assignment {});
140  }
141  return *this;
142  }
143 
148  {
149  clear();
150  shrink_to_fit();
151  }
152 
156  void swap(RAJAVec& other)
157  {
158  swap_private(other, propagate_on_container_swap {});
159  }
160 
164  pointer data() { return m_data; }
165 
167  const_pointer data() const { return m_data; }
168 
172  iterator end() { return m_data + m_size; }
173 
175  const_iterator end() const { return m_data + m_size; }
176 
178  const_iterator cend() const { return m_data + m_size; }
179 
183  iterator begin() { return m_data; }
184 
186  const_iterator begin() const { return m_data; }
187 
189  const_iterator cbegin() const { return m_data; }
190 
194  bool empty() const { return (m_size == 0); }
195 
199  size_type size() const { return m_size; }
200 
204  size_type capacity() const { return m_capacity; }
205 
209  allocator_type get_allocator() const { return m_allocator; }
210 
214  void reserve(size_type target_capacity) { grow_cap(target_capacity); }
215 
219  void shrink_to_fit() { shrink_cap(m_size); }
220 
224  void clear() { destroy_items_after(0); }
225 
231  RAJA_INLINE
232  void resize(size_type new_size)
233  {
234  if (new_size >= size())
235  {
236  reserve(new_size);
237  construct_items_back(new_size);
238  }
239  else
240  {
241  destroy_items_after(new_size);
242  }
243  }
244 
250  RAJA_INLINE
251  void resize(size_type new_size, const_reference new_value)
252  {
253  if (new_size >= size())
254  {
255  reserve(new_size);
256  construct_items_back(new_size, new_value);
257  }
258  else
259  {
260  destroy_items_after(new_size);
261  }
262  }
263 
267  reference operator[](difference_type i) { return m_data[i]; }
268 
270  const_reference operator[](difference_type i) const { return m_data[i]; }
271 
275  reference front() { return m_data[0]; }
276 
278  const_reference front() const { return m_data[0]; }
279 
283  reference back() { return m_data[m_size - 1]; }
284 
286  const_reference back() const { return m_data[m_size - 1]; }
287 
292  void push_front(const_reference item) { emplace_front_private(item); }
293 
295  void push_front(value_type&& item) { emplace_front_private(std::move(item)); }
296 
298  template<typename... Os>
299  void emplace_front(Os&&... os)
300  {
301  emplace_front_private(std::forward<Os>(os)...);
302  }
303 
307  void push_back(const_reference item) { emplace_back_private(item); }
308 
310  void push_back(value_type&& item) { emplace_back_private(std::move(item)); }
311 
313  template<typename... Os>
314  void emplace_back(Os&&... os)
315  {
316  emplace_back_private(std::forward<Os>(os)...);
317  }
318 
322  void pop_back() { destroy_items_after(m_size - 1); }
323 
324 private:
325  pointer m_data;
326  allocator_type m_allocator;
327  size_type m_capacity;
328  size_type m_size;
329 
334  void copy_assign_private(RAJAVec const& rhs, std::true_type)
335  {
336  if (m_allocator != rhs.m_allocator)
337  {
338  clear();
339  shrink_to_fit();
340  m_allocator = rhs.m_allocator;
341  }
342 
343  copy_assign_private(rhs, std::false_type {});
344  }
345 
350  void copy_assign_private(RAJAVec const& rhs, std::false_type)
351  {
352  reserve(rhs.size());
353  if (size() < rhs.size())
354  {
355  copy_assign_items(0, size(), rhs.data());
356  copy_construct_items_back(rhs.size(), rhs.data());
357  }
358  else
359  {
360  copy_assign_items(0, rhs.size(), rhs.data());
361  destroy_items_after(size());
362  }
363  }
364 
369  void move_assign_private(RAJAVec&& rhs, std::true_type)
370  {
371  clear();
372  shrink_to_fit();
373 
374  m_data = rhs.m_data;
375  m_allocator = std::move(rhs.m_allocator);
376  m_capacity = rhs.m_capacity;
377  m_size = rhs.m_size;
378 
379  rhs.m_data = nullptr;
380  rhs.m_capacity = 0;
381  rhs.m_size = 0;
382  }
383 
388  void move_assign_private(RAJAVec&& rhs, std::false_type)
389  {
390  if (m_allocator == rhs.m_allocator)
391  {
392  clear();
393  shrink_to_fit();
394 
395  m_data = rhs.m_data;
396  m_capacity = rhs.m_capacity;
397  m_size = rhs.m_size;
398 
399  rhs.m_data = nullptr;
400  rhs.m_capacity = 0;
401  rhs.m_size = 0;
402  }
403  else
404  {
405  reserve(rhs.size());
406  if (size() < rhs.size())
407  {
408  move_assign_items(0, size(), rhs.data());
409  move_construct_items_back(rhs.size(), rhs.data());
410  }
411  else
412  {
413  move_assign_items(0, rhs.size(), rhs.data());
414  destroy_items_after(size());
415  }
416  }
417  }
418 
422  void swap_private(RAJAVec& other, std::true_type)
423  {
424  using std::swap;
425  swap(m_data, other.m_data);
426  swap(m_allocator, other.m_allocator);
427  swap(m_capacity, other.m_capacity);
428  swap(m_size, other.m_size);
429  }
430 
434  void swap_private(RAJAVec& other, std::false_type)
435  {
436  using std::swap;
437  swap(m_data, other.m_data);
438  swap(m_capacity, other.m_capacity);
439  swap(m_size, other.m_size);
440  }
441 
442  //
443  // Copy items [first, last) from o_data.
444  //
445  void copy_assign_items(size_type first, size_type last, const_pointer o_data)
446  {
447  for (size_type i = first; i < last; ++i)
448  {
449  m_data[i] = o_data[i];
450  }
451  }
452 
453  //
454  // Move items [first, last) from o_data.
455  //
456  void move_assign_items(size_type first, size_type last, pointer o_data)
457  {
458  for (size_type i = first; i < last; ++i)
459  {
460  m_data[i] = std::move(o_data[i]);
461  }
462  }
463 
464  //
465  // Construct items [m_size, new_size) from args.
466  //
467  template<typename... Os>
468  void construct_items_back(size_type new_size, Os&&... os)
469  {
470  for (; m_size < new_size; ++m_size)
471  {
472  allocator_traits_type::construct(m_allocator, m_data + m_size,
473  std::forward<Os>(os)...);
474  }
475  }
476 
477  //
478  // Copy construct items [m_size, new_size) from o_data.
479  //
480  void copy_construct_items_back(size_type new_size, const_pointer o_data)
481  {
482  for (; m_size < new_size; ++m_size)
483  {
484  allocator_traits_type::construct(m_allocator, m_data + m_size,
485  o_data[m_size]);
486  }
487  }
488 
489  //
490  // Move construct items [m_size, new_size) from o_data.
491  //
492  void move_construct_items_back(size_type new_size, pointer o_data)
493  {
494  for (; m_size < new_size; ++m_size)
495  {
496  allocator_traits_type::construct(m_allocator, m_data + m_size,
497  std::move(o_data[m_size]));
498  }
499  }
500 
501  //
502  // Destroy items [new_end, m_size).
503  //
504  void destroy_items_after(size_type new_end)
505  {
506  for (; m_size > new_end; --m_size)
507  {
508  allocator_traits_type::destroy(m_allocator, m_data + m_size - 1);
509  }
510  }
511 
512  //
513  // Add an item to the front, shifting all existing items back one.
514  //
515  template<typename... Os>
516  void emplace_front_private(Os&&... os)
517  {
518  reserve(m_size + 1);
519 
520  if (m_size > 0)
521  {
522  size_type i = m_size;
523  allocator_traits_type::construct(m_allocator, m_data + i,
524  std::move(m_data[i - 1]));
525  for (--i; i > 0; --i)
526  {
527  m_data[i] = std::move(m_data[i - 1]);
528  }
529  allocator_traits_type::destroy(m_allocator, m_data);
530  }
531  allocator_traits_type::construct(m_allocator, m_data,
532  std::forward<Os>(os)...);
533  m_size++;
534  }
535 
536  //
537  // Add an item to the back.
538  //
539  template<typename... Os>
540  void emplace_back_private(Os&&... os)
541  {
542  reserve(m_size + 1);
543  allocator_traits_type::construct(m_allocator, m_data + m_size,
544  std::forward<Os>(os)...);
545  m_size++;
546  }
547 
548  //
549  // The following private members and methods provide a quick and dirty
550  // memory allocation scheme to mimick std::vector behavior without
551  // relying on STL directly.
552  //
553  static constexpr const size_type s_init_cap = 8;
554  static constexpr const double s_grow_fac = 1.5;
555 
556  //
557  // Get the next value for capacity given a target and minimum.
558  //
559  size_type get_next_cap(size_type target_size)
560  {
561  size_type next_cap = s_init_cap;
562  if (m_capacity != 0)
563  {
564  next_cap = static_cast<size_type>(m_capacity * s_grow_fac);
565  }
566  return std::max(target_size, next_cap);
567  }
568 
569  //
570  // Increase capacity to at least target_size.
571  //
572  void grow_cap(size_type target_size)
573  {
574  if (m_capacity < target_size)
575  {
576  change_cap(get_next_cap(target_size));
577  }
578  }
579 
580  //
581  // Decrease capacity to at most target_size or size if size is greater.
582  //
583  void shrink_cap(size_type target_size)
584  {
585  if (m_capacity > target_size)
586  {
587  change_cap(std::max(m_size, target_size));
588  }
589  }
590 
591  //
592  // Reallocate to change capacity to next_cap.
593  // NOTE: assumes next_cap >= size()
594  //
595  void change_cap(size_type next_cap)
596  {
597  pointer tdata = nullptr;
598  if (next_cap != 0)
599  {
600  tdata = allocator_traits_type::allocate(m_allocator, next_cap);
601  }
602 
603  if (m_data)
604  {
605  for (size_type i = 0; i < m_size; ++i)
606  {
607  allocator_traits_type::construct(m_allocator, tdata + i,
608  std::move(m_data[i]));
609  allocator_traits_type::destroy(m_allocator, m_data + i);
610  }
611  allocator_traits_type::deallocate(m_allocator, m_data, m_capacity);
612  }
613 
614  m_data = tdata;
615  m_capacity = next_cap;
616  }
617 };
618 
619 } // namespace RAJA
620 
621 #endif // closing endif for header file include guard
Header file defining prototypes for routines used to manage memory for CPU reductions and other opera...
Class template that provides a simple vector implementation sufficient to insulate RAJA entities from...
Definition: RAJAVec.hpp:56
void push_front(value_type &&item)
Definition: RAJAVec.hpp:295
iterator begin()
Definition: RAJAVec.hpp:183
void emplace_back(Os &&... os)
Definition: RAJAVec.hpp:314
RAJAVec(RAJAVec &&other)
Definition: RAJAVec.hpp:108
const_iterator cend() const
Definition: RAJAVec.hpp:178
void pop_back()
Definition: RAJAVec.hpp:322
size_type capacity() const
Definition: RAJAVec.hpp:204
RAJAVec & operator=(RAJAVec &&rhs)
Definition: RAJAVec.hpp:134
void clear()
Definition: RAJAVec.hpp:224
const_iterator cbegin() const
Definition: RAJAVec.hpp:189
void emplace_front(Os &&... os)
Definition: RAJAVec.hpp:299
RAJA_INLINE void resize(size_type new_size)
Definition: RAJAVec.hpp:232
iterator end()
Definition: RAJAVec.hpp:172
~RAJAVec()
Definition: RAJAVec.hpp:147
const_pointer data() const
Definition: RAJAVec.hpp:167
void swap(RAJAVec &other)
Definition: RAJAVec.hpp:156
size_type size() const
Definition: RAJAVec.hpp:199
void reserve(size_type target_capacity)
Definition: RAJAVec.hpp:214
const_reference front() const
Definition: RAJAVec.hpp:278
const value_type * const_iterator
Definition: RAJAVec.hpp:75
const_reference back() const
Definition: RAJAVec.hpp:286
void push_back(const_reference item)
Definition: RAJAVec.hpp:307
RAJA_INLINE void resize(size_type new_size, const_reference new_value)
Definition: RAJAVec.hpp:251
std::size_t size_type
Definition: RAJAVec.hpp:68
const value_type & const_reference
Definition: RAJAVec.hpp:71
bool empty() const
Definition: RAJAVec.hpp:194
reference front()
Definition: RAJAVec.hpp:275
const_iterator end() const
Definition: RAJAVec.hpp:175
RAJAVec & operator=(const RAJAVec &rhs)
Definition: RAJAVec.hpp:122
value_type & reference
Definition: RAJAVec.hpp:70
RAJAVec(const RAJAVec &other)
Definition: RAJAVec.hpp:93
allocator_type get_allocator() const
Definition: RAJAVec.hpp:209
std::ptrdiff_t difference_type
Definition: RAJAVec.hpp:69
void push_front(const_reference item)
Definition: RAJAVec.hpp:292
typename allocator_traits_type::const_pointer const_pointer
Definition: RAJAVec.hpp:73
value_type * iterator
Definition: RAJAVec.hpp:74
typename allocator_traits_type::pointer pointer
Definition: RAJAVec.hpp:72
reference operator[](difference_type i)
Definition: RAJAVec.hpp:267
void push_back(value_type &&item)
Definition: RAJAVec.hpp:310
const_reference operator[](difference_type i) const
Definition: RAJAVec.hpp:270
T value_type
Definition: RAJAVec.hpp:66
void shrink_to_fit()
Definition: RAJAVec.hpp:219
reference back()
Definition: RAJAVec.hpp:283
const_iterator begin() const
Definition: RAJAVec.hpp:186
RAJAVec(size_type init_cap=0, const allocator_type &a=allocator_type())
Definition: RAJAVec.hpp:80
Allocator allocator_type
Definition: RAJAVec.hpp:67
pointer data()
Definition: RAJAVec.hpp:164
Definition: AlignedRangeIndexSetBuilders.cpp:35
RAJA_HOST_DEVICE constexpr RAJA_INLINE Result max(Args... args)
Definition: foldl.hpp:155
Definition: ListSegment.hpp:416
RAJA_INLINE void swap(RAJA::TypedListSegment< StorageT > &a, RAJA::TypedListSegment< StorageT > &b)
Specialization of std::swap for TypedListSegment.
Definition: ListSegment.hpp:420