31 #include <type_traits> 52 template <
typename T,
size_t N = 512,
bool Safe = true>
90 for (
const auto& elem : other) {
93 assert(
m_size == other.m_size);
94 assert(
m_blocks.size() == other.m_blocks.size());
106 if (
this != &other) {
108 for (
const auto& elem : other) {
111 assert(
m_size == other.m_size);
112 assert(
m_blocks.size() == other.m_blocks.size());
120 if (
this != &other) {
122 m_blocks = std::move(other.m_blocks);
123 std::swap(
m_size, other.m_size);
136 T&
at(std::size_t pos)
139 throw std::out_of_range(
"CompactStorage: index out of range.");
141 return *
static_cast<T*
>(
static_cast<void*
>(&(
m_blocks[pos / N][pos % N])));
145 const T&
at(std::size_t pos)
const 148 throw std::out_of_range(
"CompactStorage: index out of range.");
150 return *
static_cast<const T*
>(
static_cast<const void*
>(&(
m_blocks[pos / N][pos % N])));
159 return *
static_cast<const T*
>(
static_cast<const void*
>(&
m_blocks[(
m_size - 1) / N][(
m_size - 1) % N]));
163 T&
operator[](
size_t pos) {
return *
static_cast<T*
>(
static_cast<void*
>(&(
m_blocks[pos / N][pos % N]))); }
168 return *
static_cast<const T*
>(
static_cast<const void*
>(&(
m_blocks[pos / N][pos % N])));
223 if (new_size <
size()) {
229 const size_type new_block_count = 1 + (new_size - 1) / N;
236 }
else if (new_size >
size()) {
248 assert((
size() == new_size));
254 if (new_size <
size()) {
256 }
else if (new_size >
size()) {
261 assert((
size() == new_size));
269 for (
auto& i : *
this) {
279 assert(m_blocks.size() == 0);
283 template <
class... Args>
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)...);
292 template <
class... Args>
296 return new (memory) T(std::forward<Args>(args)...);
304 throw std::logic_error(
"CompactStorage::pop_back called on empty object.");
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];
323 return new (memory) T(obj);
330 return new (memory) T(std::move(obj));
335 using Chunk =
typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
345 const size_t b =
m_size / N;
346 const size_t i =
m_size % N;
349 auto chunk =
new Chunk[N];
353 return static_cast<T*
>(
static_cast<void*
>(&((
m_blocks[b])[i])));
364 template <
typename T,
size_t N = 512,
bool Safe = true>
373 template <
typename T,
size_t N = 512,
bool Safe = true>
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.
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 'N').
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.
typename std::aligned_storage< sizeof(Person), std::alignment_of< Person >::value >::type Chunk
POD type with same alignment requirement as for T's.
~SegmentedVector()
Destructor.
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.
Namespace for the simulator and related classes.
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