VPTissue Reference Manual
SegmentedVector.h
Go to the documentation of this file.
1 #ifndef CONTAINER_SEGMENTED_VECTOR_H_
2 #define CONTAINER_SEGMENTED_VECTOR_H_
3 /*
4  * Copyright 2011-2016 Universiteit Antwerpen
5  *
6  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
7  * the European Commission - subsequent versions of the EUPL (the "Licence");
8  * You may not use this work except in compliance with the Licence.
9  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the Licence is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the Licence for the specific language governing
15  * permissions and limitations under the Licence.
16  */
22 #include "SVIterator.h"
23 
24 #include <array>
25 #include <cassert>
26 #include <iterator>
27 #include <limits>
28 #include <stdexcept>
29 #include <type_traits>
30 #include <utility>
31 #include <vector>
32 
33 namespace SimPT_Sim {
34 namespace Container {
35 
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  SegmentedVector() : m_size(0) {}
69 
71  SegmentedVector(const self_type& other)
72  : m_size(0)
73  {
74  m_blocks.reserve(other.m_blocks.size());
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  }
81 
84  : m_blocks(std::move(other.m_blocks)), m_size(other.m_size)
85  {
86  other.m_size = 0;
87  }
88 
91  {
92  if (this != &other) {
93  clear();
94  m_blocks.reserve(other.m_blocks.size());
95  for (const auto& elem : other) {
96  push_back(elem);
97  }
98  assert(m_size == other.m_size);
99  assert(m_blocks.size() == other.m_blocks.size());
100  }
101  return *this;
102  }
103 
106  {
107  if (this != &other) {
108  clear();
109  m_blocks = std::move(other.m_blocks);
110  std::swap(m_size, other.m_size);
111  }
112  return *this;
113  }
114 
115 
118  {
119  clear();
120  }
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()
150  {
151  return *static_cast<T*>(static_cast<void*>(&m_blocks[(m_size-1)/N][(m_size-1)%N]));
152  }
153 
155  const T& back() const
156  {
157  return *static_cast<const T*>(static_cast<const void*>(&m_blocks[(m_size-1)/N][(m_size-1)%N]));
158  }
159 
161  T& operator[] (size_t pos)
162  {
163  return *static_cast<T*>(static_cast<void*>(&(m_blocks[pos/N][pos%N])));
164  }
165 
167  const T& operator[] (size_t pos) const
168  {
169  return *static_cast<const T*>(static_cast<const void*>(&(m_blocks[pos/N][pos%N])));
170  }
171 
172  // ==================================================================
173  // Iterators
174  // ==================================================================
175 
178  {
179  return (m_size == 0) ? end() : iterator(0, this);
180  }
181 
184  {
185  return (m_size == 0) ? end() : const_iterator(0, this);
186  }
187 
190  {
191  return (m_size == 0) ? end() : const_iterator(0, this);
192  }
193 
196  {
197  return iterator(iterator::m_end, this);
198  }
199 
202  {
203  return const_iterator(const_iterator::m_end, this);
204  }
205 
208  {
209  return const_iterator(const_iterator::m_end, this);
210  }
211 
212  // ==================================================================
213  // Capacity
214  // ==================================================================
215 
217  bool empty() const
218  {
219  return m_size == 0;
220  }
221 
223  std::size_t get_block_count() const
224  {
225  return m_blocks.size();
226  }
227 
229  std::size_t get_elements_per_block() const
230  {
231  return N;
232  }
233 
235  std::size_t size() const
236  {
237  return m_size;
238  }
239 
240  // ==================================================================
241  // Modifiers
242  // ==================================================================
243 
245  void clear()
246  {
247  for (auto& i : *this) {
248  i.~T();
249  }
250  for (auto p : m_blocks) {
251  delete[] p;
252  }
253  m_blocks.clear();
254  m_size = 0;
255  }
256 
258  template <class... Args>
259  T* emplace_back(Args&&... args)
260  {
261  T* memory = this->get_chunk();
262  return new (memory) T(args...); // construct new object
263  }
264 
266  void pop_back()
267  {
268  // No pop on empty container.
269  if (m_size <= 0) {
270  throw std::logic_error("CompactStorage::pop_back called on empty object.");
271  }
272 
273  // Element destruction.
274  at(m_size-1).~T();
275  --m_size;
276 
277  // If tail block vacated, release it.
278  const size_t last_block_index = m_blocks.size() - 1;
279  if (m_size <= last_block_index * N) {
280  delete[] m_blocks[last_block_index];
281  m_blocks.pop_back();
282  }
283  }
284 
286  T* push_back(const T& obj)
287  {
288  T* memory = get_chunk();
289  return new (memory) T(obj); // copy-construct new object
290  }
291 
293  T* push_back(T&& obj)
294  {
295  T* memory = get_chunk();
296  return new (memory) T(std::move(obj)); // move-construct new object
297  }
298 
299 private:
301  using Chunk = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
302 
303 private:
304  friend class SVIterator<T, N>;
305  friend class SVIterator<T, N, T*, T&, false>;
306 
307 private:
309  T* get_chunk()
310  {
311  const size_t b = m_size / N; // Index of block in vector m_blocks
312  const size_t i = m_size % N; // Offset of chunk within its block
313 
314  if (b == m_blocks.size()) { // Out of buffers, last buffer is full
315  Chunk* chunk = new Chunk[N];
316  m_blocks.push_back(chunk);
317  }
318  ++m_size;
319  return static_cast<T*>(static_cast<void*>(&((m_blocks[b])[i])));
320  }
321 
322 private:
323  std::vector<Chunk*> m_blocks;
324  size_t m_size;
325 };
326 
327 } // namespace
328 } // namespace
329 
330 #endif // end_of_include_guard
T * emplace_back(Args &&...args)
Constructs element in-place at the end.
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.
SegmentedVector(self_type &&other)
Move constructor.
STL namespace.
bool empty() const
Checks whether container is empty.
T & operator[](size_t pos)
Access specified element (no bounds checking).
const_iterator end() const
Returns a const_iterator to the end of the container.
std::size_t get_block_count() const
Returns number of currently allocated blocks.
SegmentedVector(const self_type &other)
Copy constructor.
void clear()
Clears the content.
Namespace for the core simulator.
T & back()
Access the last element.
const T & back() const
Access the last element.
T * push_back(T &&obj)
Adds element to end.
const_iterator cbegin() const
Returns a const_iterator to the beginning of the container.
std::size_t size() const
Returns the number of elements.
std::size_t get_elements_per_block() const
Returns number of elements block (template parameter 'N').
T * push_back(const T &obj)
Adds element to end.
self_type & operator=(const self_type &other)
Copy assignment.
iterator begin()
Returns an iterator to the beginning of the container.
void pop_back()
Removes the last element.
const_iterator cend() const
Returns a const_iterator to the end.
Interface/Implementation for SVIterator.
T & at(std::size_t pos)
Access specified element with bounds checking.
Implementation of iterator for SegmentedVector.
Definition: SVIterator.h:62
const T & at(std::size_t pos) const
Access specified element with bounds checking.
Container that stores objects "almost contiguously" and guarantees that pointers/iterators are not in...