MRPT  1.9.9
vector_with_small_size_optimization.h
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 #pragma once
10 
11 #include <mrpt/core/aligned_allocator.h> // aligned_allocator_cpp11
12 #include <array>
13 #include <cstddef> // size_t
14 #include <type_traits> // conditional_t, ...
15 #include <vector>
16 
17 namespace mrpt::containers
18 {
20 {
21  operator const bool&() const { return b; }
22  operator bool&() { return b; }
23 
24  bool b;
25 };
26 
27 /** Container that transparently and dynamically switches between a std::array
28  * and std::vector. Used to avoid heap allocations with small vectors.
29  *
30  * \note In `#include <mrpt/containers/vector_with_small_size_optimization.h>`
31  * \ingroup mrpt_containers_grp
32  */
33 template <typename VAL, size_t small_size, size_t alignment = 16>
35 {
36  private:
37  using T =
38  std::conditional_t<std::is_same_v<VAL, bool>, UnspecializedBool, VAL>;
40  using vector =
42  using large_vec = std::vector<T, ALLOC>;
43  using small_array = std::array<T, small_size>;
44 
46  alignas(alignment) small_array m_a;
47  bool m_is_small = true;
48  size_t m_size = 0;
49 
50  public:
51  using value_type = T;
52  using reference = T&;
53  using const_reference = const T&;
54  using difference_type = typename large_vec::difference_type;
55  using size_type = typename large_vec::size_type;
56  template <typename TYPE, typename POINTER, typename REFERENCE>
58  {
59  using STORAGE = std::conditional_t<
60  std::is_same_v<POINTER, bool*>, UnspecializedBool*,
61  std::conditional_t<
62  std::is_same_v<POINTER, const bool*>, const UnspecializedBool*,
63  POINTER>>;
65 
66  public:
67  using value_type = TYPE;
68  using reference = REFERENCE;
69  using pointer = POINTER;
70  using iterator_category = std::random_access_iterator_tag;
71  using difference_type = typename large_vec::difference_type;
72  iteratorImpl() = default;
73  iteratorImpl(STORAGE ptr) : m_ptr(ptr) {}
74  self operator++()
75  {
76  self i = *this;
77  m_ptr++;
78  return i;
79  }
80  self operator--()
81  {
82  self i = *this;
83  m_ptr--;
84  return i;
85  }
86  self operator++(int)
87  {
88  m_ptr++;
89  return *this;
90  }
91  self operator--(int)
92  {
93  m_ptr--;
94  return *this;
95  }
97  {
98  self i = *this;
99  i.m_ptr += n;
100  return i;
101  }
103  {
104  self i = *this;
105  i.m_ptr -= n;
106  return i;
107  }
109  {
110  m_ptr += n;
111  return *this;
112  }
114  {
115  m_ptr -= n;
116  return *this;
117  }
118  difference_type operator-(const self& o) const
119  {
120  return m_ptr - o.m_ptr;
121  }
122  REFERENCE operator*() { return *m_ptr; }
123  const REFERENCE operator*() const { return *m_ptr; }
124  POINTER operator->() { return m_ptr; }
125  const POINTER operator->() const { return m_ptr; }
126  bool operator==(const self& o) { return m_ptr == o.m_ptr; }
127  bool operator!=(const self& o) { return m_ptr != o.m_ptr; }
128 
129  private:
130  STORAGE m_ptr{nullptr};
131  };
132 
133  using iterator = iteratorImpl<VAL, VAL*, VAL&>;
134  using const_iterator = iteratorImpl<VAL, const VAL*, const VAL&>;
135 
137  {
138  if (m_size)
139  {
140  if (m_is_small && n > small_size)
141  {
142  m_v.assign(m_a.begin(), m_a.begin() + m_size);
143  }
144  else if (!m_is_small && n <= small_size)
145  {
146  std::copy(m_v.begin(), m_v.begin() + n, m_a.begin());
147  }
148  }
149  m_size = n;
150  m_is_small = (n <= small_size);
151  if (!m_is_small)
152  {
153  m_v.resize(m_size);
154  }
155  }
156 
157  size_t size() const { return m_size; }
158  bool empty() const { return m_size == 0; }
159 
161 
163  {
164  return m_is_small ? m_a[n] : m_v[n];
165  }
166 
168  {
169  return m_is_small ? m_a[m_size - 1] : m_v.back();
170  }
171  reference back() { return m_is_small ? m_a[m_size - 1] : m_v.back(); }
172 
174  {
175  return m_is_small ? m_a.front() : m_v.front();
176  }
177  reference front() { return m_is_small ? m_a.front() : m_v.front(); }
178 
179  void swap(vector& x)
180  {
181  if (m_is_small & x.m_is_small)
182  {
183  m_a.swap(x.m_a);
184  }
185  else if (!m_is_small && !x.m_is_small)
186  {
187  m_v.swap(x.m_v);
188  }
189  else if (!m_is_small && x.m_is_small)
190  {
191  std::copy(x.m_a.begin(), x.m_a.begin() + x.m_size, m_a.begin());
192  x.m_v.swap(m_v);
193  }
194  else
195  {
196  m_v.swap(x.m_v);
197  std::copy(m_a.begin(), m_a.begin() + m_size, x.m_a.begin());
198  }
199  std::swap(m_size, x.m_size);
200  std::swap(m_is_small, x.m_is_small);
201  }
202 
203  iterator begin() noexcept { return m_is_small ? m_a.data() : m_v.data(); }
204  const_iterator begin() const noexcept
205  {
206  return m_is_small ? m_a.data() : m_v.data();
207  }
208 
209  iterator end() noexcept
210  {
211  return m_is_small ? m_a.data() + m_size : m_v.data() + m_size;
212  }
213  const_iterator end() const noexcept
214  {
215  return m_is_small ? m_a.data() + m_size : m_v.data() + m_size;
216  }
217 };
218 
219 } // namespace mrpt::containers
std::conditional_t< std::is_same_v< VAL, bool >, UnspecializedBool, VAL > T
Container that transparently and dynamically switches between a std::array and std::vector.
GLenum GLsizei n
Definition: glext.h:5136
Definition: inflate.h:37
Aligned allocator that is compatible with C++11.
std::conditional_t< std::is_same_v< POINTER, bool * >, UnspecializedBool *, std::conditional_t< std::is_same_v< POINTER, const bool * >, const UnspecializedBool *, POINTER > > STORAGE
GLenum GLint x
Definition: glext.h:3542



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 8fe78517f Sun Jul 14 19:43:28 2019 +0200 at lun oct 28 02:10:00 CET 2019