Stride Reference Manual  - generated for commit 9643b11
SegmentedVector.h
Go to the documentation of this file.
1 /*
2  * This is free software: you can redistribute it and/or modify it
3  * under the terms of the GNU General Public License as published by
4  * the Free Software Foundation, either version 3 of the License, or
5  * any later version.
6  * The software is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  * You should have received a copy of the GNU General Public License
11  * along with the software. If not, see <http://www.gnu.org/licenses/>.
12  *
13  * Copyright 2018, Kuylen E, Willem L, Broeckhove J
14  */
15 
21 #pragma once
22 
23 #include "SVIterator.h"
24 
25 #include <array>
26 #include <cassert>
27 #include <iostream>
28 #include <iterator>
29 #include <limits>
30 #include <stdexcept>
31 #include <type_traits>
32 #include <utility>
33 #include <vector>
34 
35 namespace stride {
36 namespace util {
37 
52 template <typename T, size_t N = 512, bool Safe = true>
54 {
55 public:
56  // ==================================================================
57  // Member types
58  // ==================================================================
59  using value_type = T;
60  using size_type = std::size_t;
64 
65  // ==================================================================
66  // Construction / Copy / Move / Destruction
67  // ==================================================================
68 
73  explicit SegmentedVector() : m_blocks(), m_size(0) {}
74 
79  explicit SegmentedVector(size_type i) : m_blocks(), m_size(0) { resize(i); }
80 
85  explicit SegmentedVector(size_type i, const value_type& value) : m_blocks(), m_size(0) { resize(i, value); }
86 
88  explicit SegmentedVector(const self_type& other) : m_blocks(), m_size(0)
89  {
90  for (const auto& elem : other) {
91  push_back(elem);
92  }
93  assert(m_size == other.m_size);
94  assert(m_blocks.size() == other.m_blocks.size());
95  }
96 
98  explicit SegmentedVector(self_type&& other) noexcept : m_blocks(std::move(other.m_blocks)), m_size(other.m_size)
99  {
100  other.m_size = 0;
101  }
102 
105  {
106  if (this != &other) {
107  clear();
108  for (const auto& elem : other) {
109  push_back(elem);
110  }
111  assert(m_size == other.m_size);
112  assert(m_blocks.size() == other.m_blocks.size());
113  }
114  return *this;
115  }
116 
119  {
120  if (this != &other) {
121  clear();
122  m_blocks = std::move(other.m_blocks);
123  std::swap(m_size, other.m_size);
124  }
125  return *this;
126  }
127 
130 
131  // ==================================================================
132  // Element access
133  // ==================================================================
134 
136  T& at(std::size_t pos)
137  {
138  if (pos >= m_size) {
139  throw std::out_of_range("CompactStorage: index out of range.");
140  }
141  return *static_cast<T*>(static_cast<void*>(&(m_blocks[pos / N][pos % N])));
142  }
143 
145  const T& at(std::size_t pos) const
146  {
147  if (pos >= m_size) {
148  throw std::out_of_range("CompactStorage: index out of range.");
149  }
150  return *static_cast<const T*>(static_cast<const void*>(&(m_blocks[pos / N][pos % N])));
151  }
152 
154  T& back() { return *static_cast<T*>(static_cast<void*>(&m_blocks[(m_size - 1) / N][(m_size - 1) % N])); }
155 
157  const T& back() const
158  {
159  return *static_cast<const T*>(static_cast<const void*>(&m_blocks[(m_size - 1) / N][(m_size - 1) % N]));
160  }
161 
163  T& operator[](size_t pos) { return *static_cast<T*>(static_cast<void*>(&(m_blocks[pos / N][pos % N]))); }
164 
166  const T& operator[](size_t pos) const
167  {
168  return *static_cast<const T*>(static_cast<const void*>(&(m_blocks[pos / N][pos % N])));
169  }
170 
171  // ==================================================================
172  // Iterators
173  // ==================================================================
174 
176  iterator begin() { return (m_size == 0) ? end() : iterator(0, this); }
177 
179  const_iterator begin() const { return (m_size == 0) ? end() : const_iterator(0, this); }
180 
182  const_iterator cbegin() const { return (m_size == 0) ? end() : const_iterator(0, this); }
183 
185  iterator end() { return iterator(size(), this); }
186 
188  const_iterator end() const { return const_iterator(size(), this); }
189 
191  const_iterator cend() const { return const_iterator(size(), this); }
192 
193  // ==================================================================
194  // Capacity
195  // ==================================================================
196 
198  std::size_t capacity() const { return N * m_blocks.size(); }
199 
201  bool empty() const { return m_size == 0; }
202 
204  std::size_t get_block_count() const { return m_blocks.size(); }
205 
207  std::size_t get_elements_per_block() const { return N; }
208 
210  std::size_t size() const { return m_size; }
211 
212  // ==================================================================
213  // Modifiers
214  // ==================================================================
215 
221  void resize(size_type new_size)
222  {
223  if (new_size < size()) {
224  if (Safe) {
225  for (size_type i = m_size - 1; new_size - 1 < i; --i) {
226  pop_back();
227  }
228  } else {
229  const size_type new_block_count = 1 + (new_size - 1) / N;
230  while (new_block_count < get_block_count()) {
231  delete[] m_blocks[m_blocks.size() - 1];
232  m_blocks.pop_back();
233  }
234  m_size = new_size;
235  }
236  } else if (new_size > size()) {
237  if (Safe) {
238  for (size_type i = size(); i < new_size; ++i) {
239  push_back(std::move(T()));
240  }
241  } else {
242  while (new_size > capacity()) {
243  m_blocks.push_back(new Chunk[N]);
244  }
245  m_size = new_size;
246  }
247  }
248  assert((size() == new_size));
249  assert((size() <= capacity()));
250  }
251 
252  void resize(size_type new_size, const value_type& value)
253  {
254  if (new_size < size()) {
255  resize(new_size);
256  } else if (new_size > size()) {
257  for (size_type i = size(); i < new_size; ++i) {
258  push_back(value);
259  }
260  }
261  assert((size() == new_size));
262  assert((size() <= capacity()));
263  }
264 
266  void clear()
267  {
268  if (Safe) {
269  for (auto& i : *this) {
270  i.~T();
271  }
272  }
273  for (auto p : m_blocks) {
274  delete[] p;
275  }
276  m_blocks.clear();
277  m_size = 0;
278  assert(size() == 0);
279  assert(m_blocks.size() == 0);
280  }
281 
283  template <class... Args>
284  T* emplace(size_type pos, Args&&... args)
285  {
286  assert(0 <= pos && pos < m_size);
287  T* memory = static_cast<T*>(static_cast<void*>(&(m_blocks[pos / N][pos % N])));
288  return new (memory) T(std::forward<Args>(args)...); // construct new object
289  }
290 
292  template <class... Args>
293  T* emplace_back(Args&&... args)
294  {
295  T* memory = this->get_chunk();
296  return new (memory) T(std::forward<Args>(args)...); // construct new object
297  }
298 
300  void pop_back()
301  {
302  // No pop on empty container.
303  if (m_size <= 0) {
304  throw std::logic_error("CompactStorage::pop_back called on empty object.");
305  }
306 
307  // Element destruction.
308  at(m_size - 1).~T();
309  --m_size;
310 
311  // If tail block vacated, release it.
312  const size_t last_block_index = m_blocks.size() - 1;
313  if (m_size <= last_block_index * N) {
314  delete[] m_blocks[last_block_index];
315  m_blocks.pop_back();
316  }
317  }
318 
320  T* push_back(const T& obj)
321  {
322  T* memory = get_chunk();
323  return new (memory) T(obj); // copy-construct new object
324  }
325 
327  T* push_back(T&& obj)
328  {
329  T* memory = get_chunk();
330  return new (memory) T(std::move(obj)); // move-construct new object
331  }
332 
333 private:
335  using Chunk = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
336 
337 private:
338  friend class SVIterator<T, N, Safe>;
339  friend class SVIterator<T, N, Safe, T*, T&, false>;
340 
341 private:
344  {
345  const size_t b = m_size / N; // Index of block in vector m_blocks
346  const size_t i = m_size % N; // Offset of chunk within its block
347 
348  if (b == m_blocks.size()) { // Out of buffers, last buffer is full
349  auto chunk = new Chunk[N];
350  m_blocks.push_back(chunk);
351  }
352  ++m_size;
353  return static_cast<T*>(static_cast<void*>(&((m_blocks[b])[i])));
354  }
355 
356 private:
357  std::vector<Chunk*> m_blocks;
358  size_t m_size;
359 };
360 
364 template <typename T, size_t N = 512, bool Safe = true>
366 {
367  return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend());
368 }
369 
373 template <typename T, size_t N = 512, bool Safe = true>
375 {
376  return !operator==(lhs, rhs);
377 }
378 
379 } // namespace util
380 } // namespace stride
SegmentedVector & operator=(self_type &&other) noexcept
Move assignment.
const T & operator[](size_t pos) const
Access specified element (no bounds checking).
void clear()
Clears the content.
SegmentedVector(self_type &&other) noexcept
Move constructor.
SegmentedVector & operator=(const self_type &other)
Copy assignment.
iterator begin()
Returns an iterator to the beginning of the container.
T & operator[](size_t pos)
Access specified element (no bounds checking).
SegmentedVector(size_type i, const value_type &value)
Construct with given number of elements and INITIALIZE them with value.
iterator end()
Returns an iterator to the end of the container.
const_iterator end() const
Returns a const_iterator to the end of the container.
SVIterator< T, N, Safe > const_iterator
SegmentedVector(const self_type &other)
Copy constructor.
const_iterator cbegin() const
Returns a const_iterator to the beginning of the container.
Interface/Implementation for SVIterator.
T * emplace(size_type pos, Args &&...args)
Constructs element in-place at position pos.
bool empty() const
Checks whether container is empty.
const T & back() const
Access the last element.
STL namespace.
void resize(size_type new_size, const value_type &value)
std::size_t capacity() const
Returns number of elements that can be stored without allocating additional blocks.
T * get_chunk()
Get next available chunk for element construction with placement new.
Container that stores objects "almost contiguously" (in a chain of blocks) and guarantees that pointe...
const_iterator begin() const
Returns a const_iterator to the beginning of the container.
void pop_back()
Removes the last element.
void resize(size_type new_size)
Increases the number of elements (but DOES NOT INITIALIZE the additional elements) or pops elements (...
T & back()
Access the last element.
std::size_t get_elements_per_block() const
Returns number of elements block (template parameter &#39;N&#39;).
std::vector< Chunk * > m_blocks
Vector registers pointers to blocks of chunks.
T * push_back(const T &obj)
Adds element to end.
std::size_t get_block_count() const
Returns number of currently allocated blocks.
const T & at(std::size_t pos) const
Access specified element with bounds checking.
T * push_back(T &&obj)
Adds element to end.
bool operator!=(const SegmentedVector< T, N, Safe > &lhs, const SegmentedVector< T, N, Safe > &rhs)
Helper function for inequality test (unequal size or not all elements equal).
Implementation of iterator for SegmentedVector.
Definition: SVIterator.h:57
typename std::aligned_storage< sizeof(Person), std::alignment_of< Person >::value >::type Chunk
POD type with same alignment requirement as for T&#39;s.
bool operator==(const SegmentedVector< T, N, Safe > &lhs, const SegmentedVector< T, N, Safe > &rhs)
Helper function for equality test (equal size and all elements equal).
size_t m_size
Index of first free chunk when indexed contiguously.
std::size_t size() const
Returns the number of elements.
const_iterator cend() const
Returns a const_iterator to the end.
T * emplace_back(Args &&...args)
Constructs element in-place at the end.
T & at(std::size_t pos)
Access specified element with bounds checking.
Store and handle person data.
Definition: Person.h:34
Namespace for the simulator and related classes.
Definition: Calendar.cpp:28
SegmentedVector(size_type i)
Construct with given number of elements but DO NOT INITIALIZE them.
SegmentedVector()
Construct empty SegmentedVector.
SVIterator< T, N, Safe, T *, T &, false > iterator