Gobelijn API documentation  - generated for commit a0cbea7
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros Pages
SegmentedVector.h
Go to the documentation of this file.
1 #pragma once
2 /*
3  * Copyright 2011-2016 Universiteit Antwerpen
4  *
5  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
6  * the European Commission - subsequent versions of the EUPL (the "Licence");
7  * You may not use this work except in compliance with the Licence.
8  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the Licence is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the Licence for the specific language governing
14  * permissions and limitations under the Licence.
15  */
21 #include "SVIterator.h"
22 
23 #include <array>
24 #include <cassert>
25 #include <iterator>
26 #include <limits>
27 #include <stdexcept>
28 #include <type_traits>
29 #include <utility>
30 #include <vector>
31 
32 namespace UA_CoMP {
33 namespace Container {
34 
50 template <typename T, size_t N = 512>
52 {
53 public:
54  // ==================================================================
55  // Member types
56  // ==================================================================
57  using value_type = T;
58  using size_type = std::size_t;
62 
63  // ==================================================================
64  // Construction / Copy / Move / Destruction
65  // ==================================================================
66 
68  explicit SegmentedVector() : m_blocks(), m_size(0) {}
69 
72  SegmentedVector(const self_type& other) : m_blocks(), m_size(0)
73  {
74  reserve(other.capacity());
75  for (const auto& elem : other) {
76  push_back(elem);
77  }
78  assert(m_size == other.m_size);
79  assert(m_blocks.size() == other.m_blocks.size());
80  assert(this->capacity() == other.capacity());
81  }
82 
85  SegmentedVector(self_type&& other) noexcept : m_blocks(std::move(other.m_blocks)), m_size(other.m_size)
86  {
87  other.m_size = 0;
88  }
89 
93  {
94  if (this != &other) {
95  clear();
96  reserve(other.capacity());
97  for (const auto& elem : other) {
98  push_back(elem);
99  }
100  assert(m_size == other.m_size);
101  assert(m_blocks.size() == other.m_blocks.size());
102  assert(this->capacity() == other.capacity());
103  }
104  return *this;
105  }
106 
110  {
111  if (this != &other) {
112  clear();
113  m_blocks = std::move(other.m_blocks);
114  std::swap(m_size, other.m_size);
115  }
116  return *this;
117  }
118 
121 
122  // ==================================================================
123  // Element access
124  // ==================================================================
125 
127  T& at(std::size_t pos)
128  {
129  if (pos >= m_size) {
130  throw std::out_of_range("CompactStorage: index out of range.");
131  }
132  const size_t b = pos / N;
133  const size_t i = pos % N;
134  return *static_cast<T*>(static_cast<void*>(&(m_blocks[b][i])));
135  }
136 
138  const T& at(std::size_t pos) const
139  {
140  if (pos >= m_size) {
141  throw std::out_of_range("CompactStorage: index out of range.");
142  }
143  const size_t b = pos / N;
144  const size_t i = pos % N;
145  return *static_cast<const T*>(static_cast<const void*>(&(m_blocks[b][i])));
146  }
147 
149  T& back() { return *static_cast<T*>(static_cast<void*>(&m_blocks[(m_size - 1) / N][(m_size - 1) % N])); }
150 
152  const T& back() const
153  {
154  return *static_cast<const T*>(static_cast<const void*>(&m_blocks[(m_size - 1) / N][(m_size - 1) % N]));
155  }
156 
158  T& operator[](size_t pos) { return *static_cast<T*>(static_cast<void*>(&(m_blocks[pos / N][pos % N]))); }
159 
161  const T& operator[](size_t pos) const
162  {
163  return *static_cast<const T*>(static_cast<const void*>(&(m_blocks[pos / N][pos % N])));
164  }
165 
166  // ==================================================================
167  // Iterators
168  // ==================================================================
169 
171  iterator begin() { return (m_size == 0) ? end() : iterator(0, this); }
172 
174  const_iterator begin() const { return (m_size == 0) ? end() : const_iterator(0, this); }
175 
177  const_iterator cbegin() const { return (m_size == 0) ? end() : const_iterator(0, this); }
178 
180  iterator end() { return iterator(iterator::m_end, this); }
181 
184 
187 
188  // ==================================================================
189  // Capacity
190  // ==================================================================
191 
193  std::size_t capacity() const { return N * m_blocks.size(); }
194 
196  bool empty() const { return m_size == 0; }
197 
199  std::size_t get_block_count() const { return m_blocks.size(); }
200 
202  std::size_t get_elements_per_block() const { return N; }
203 
205  std::size_t size() const { return m_size; }
206 
207  // ==================================================================
208  // Modifiers
209  // ==================================================================
210 
212  void reserve(size_type new_capacity)
213  {
214  while (new_capacity > capacity()) {
215  m_blocks.push_back(new Chunk[N]);
216  }
217  }
218 
221  {
222  size_type req_blocks = 1 + (size() - 1) / N;
223  while (req_blocks < m_blocks.size()) {
224  delete[] m_blocks.back();
225  m_blocks.pop_back();
226  }
227  }
229  void clear()
230  {
231  for (auto& i : *this) {
232  i.~T();
233  }
234  for (auto p : m_blocks) {
235  delete[] p;
236  }
237  m_blocks.clear();
238  m_size = 0;
239  }
240 
242  template <class... Args>
243  T* emplace_back(Args&&... args)
244  {
245  T* memory = this->get_chunk();
246  return new (memory) T(std::forward<Args>(args)...); // construct new object
247  }
248 
250  void pop_back()
251  {
252  // No pop on empty container.
253  if (m_size <= 0) {
254  throw std::logic_error("CompactStorage::pop_back called on empty object.");
255  }
256 
257  // Element destruction.
258  at(m_size - 1).~T();
259  --m_size;
260 
261  // If tail block vacated, release it.
262  const size_t last_block_index = m_blocks.size() - 1;
263  if (m_size <= last_block_index * N) {
264  delete[] m_blocks[last_block_index];
265  m_blocks.pop_back();
266  }
267  }
268 
270  T* push_back(const T& obj)
271  {
272  T* memory = get_chunk();
273  return new (memory) T(obj); // copy-construct new object
274  }
275 
277  T* push_back(T&& obj)
278  {
279  T* memory = get_chunk();
280  return new (memory) T(std::move(obj)); // move-construct new object
281  }
282 
283 private:
285  using Chunk = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
286 
287 private:
288  friend class SVIterator<T, N>;
289  friend class SVIterator<T, N, T*, T&, false>;
290 
291 private:
294  {
295  const size_t b = m_size / N; // Index of block in vector m_blocks
296  const size_t i = m_size % N; // Offset of chunk within its block
297 
298  if (b == m_blocks.size()) { // Out of buffers, last buffer is full
299  auto chunk = new Chunk[N];
300  m_blocks.push_back(chunk);
301  }
302  ++m_size;
303  return static_cast<T*>(static_cast<void*>(&((m_blocks[b])[i])));
304  }
305 
306 private:
307  std::vector<Chunk*> m_blocks;
308  size_t m_size;
309 };
310 
311 } // namespace Container
312 } // namespace UA_CoMP
T * push_back(const T &obj)
Adds element to end.
std::size_t capacity() const
Returns number of elements that can be stored without allocating additional blocks.
const_iterator begin() const
Returns a const_iterator to the beginning of the container.
iterator end()
Returns an iterator to the end of the container.
T * emplace_back(Args &&...args)
Constructs element in-place at the end.
T * push_back(T &&obj)
Adds element to end.
typename std::aligned_storage< sizeof(T), std::alignment_of< T >::value >::type Chunk
POD type with same alignment requirement as for T's.
Interface/Implementation for Iterator.
const_iterator end() const
Returns a const_iterator to the end of the container.
const_iterator cend() const
Returns a const_iterator to the end.
const T & operator[](size_t pos) const
Access specified element (no bounds checking).
SegmentedVector & operator=(self_type &&other) noexcept
Move assignment (copies elements & capacity).
SegmentedVector & operator=(const self_type &other)
Copy assignment (copies elements & capacity).
void reserve(size_type new_capacity)
Allocates aditional blocks to achieve requested capacity.
bool empty() const
Checks whether container is empty.
Implementation of iterator for SegmentedVector.
Definition: SVIterator.h:55
const_iterator cbegin() const
Returns a const_iterator to the beginning of the container.
T & at(std::size_t pos)
Access specified element with bounds checking.
T & back()
Access the last element.
iterator begin()
Returns an iterator to the beginning of the container.
SegmentedVector()
Construct empty SegmentedVector.
std::size_t get_elements_per_block() const
Returns number of elements block (template parameter 'N').
std::size_t size() const
Returns the number of elements.
Container that stores objects "almost contiguously" and guarantees that pointers/iterators are not in...
std::vector< Chunk * > m_blocks
Vector registers pointers to blocks of chunks.
SVIterator< T, N, T *, T &, false > iterator
size_t m_size
Index of first free chunk when indexed contiguously.
std::size_t get_block_count() const
Returns number of currently allocated blocks.
SegmentedVector(self_type &&other) noexcept
Move constructor (moves elements & capacity).
void pop_back()
Removes the last element.
T & operator[](size_t pos)
Access specified element (no bounds checking).
const T & back() const
Access the last element.
T * get_chunk()
Get next available chunk for element construction with placement new.
SegmentedVector(const self_type &other)
Copy constructor (copies elements & capacity).
const T & at(std::size_t pos) const
Access specified element with bounds checking.
void clear()
Clears the content.
void shrink_to_fit()
Deallocates (empty) blocks to schrink capacity to fit current size.
static constexpr std::size_t m_end
One past the last element iterator position.
Definition: SVIterator.h:202