Doxygen
Loading...
Searching...
No Matches
growvector.h
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2022 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16#ifndef GROWVECTOR_H
17#define GROWVECTOR_H
18
19#include <vector>
20#include <memory>
21#include <iterator>
22
23#include "construct.h"
24
25/** @brief std::vector like container optimized for pushing elements to the back.
26 *
27 * It differs from std::vector in that it can grow without invalidating
28 * pointers to its members just like std::deque and std::list.
29 *
30 * It differs from std::deque in that the value can be incomplete
31 * just like std::vector.
32 *
33 * It differs from std::list in that it does not need to allocate each node
34 * separately and provides random access to its members.
35 *
36 * It is implemented as a vector of chunks where each chunk is a fixed capacity vector of T.
37 */
38template<class T>
40{
41 private:
42 static const size_t chunkBits = 4; // a chunk holds 2^bits elements
43 static const size_t chunkSize = 1 << chunkBits;
44 static const size_t chunkMask = chunkSize-1;
45 struct Chunk
46 {
47 Chunk() { data.reserve(chunkSize); }
48 std::vector<T> data;
49 };
50 using ChunkPtr = std::unique_ptr<Chunk>;
51
52 public:
53 /// @brief bidirectional iterator
54 template<class C,class I>
56 {
57 public:
58 using iterator_category = std::bidirectional_iterator_tag;
59 using difference_type = std::ptrdiff_t;
60 using value_type = I;
61 using pointer = I*;
62 using reference = I&;
63
64 Iterator(C &vec,size_t pos) : m_vec(&vec), m_pos(pos) {}
66 reference operator*() const { return m_vec->at(m_pos); }
67 pointer operator->() { return &m_vec->at(m_pos); }
68 Iterator& operator++() { m_pos++; return *this; }
69 Iterator operator++(int) { Iterator tmp = *this; ++(*this); return tmp; }
70 Iterator& operator--() { m_pos--; return *this; }
71 Iterator operator--(int) { Iterator tmp = *this; --(*this); return tmp; }
72 friend bool operator== (const Iterator& a, const Iterator& b) { return a.m_pos == b.m_pos; };
73 friend bool operator!= (const Iterator& a, const Iterator& b) { return a.m_pos != b.m_pos; };
74
75 private:
77 size_t m_pos;
78 };
81
82 /// returns an iterator to the beginning
83 iterator begin() { return iterator(*this,0); }
84 /// returns an iterator to the beginning
85 const_iterator begin() const { return const_iterator(*this,0); }
86
87 /// returns an iterator to the end
88 iterator end() { return iterator(*this,size()); }
89 /// returns an iterator to the end
90 const_iterator end() const { return const_iterator(*this,size()); }
91
92 /// returns the number of elements
93 size_t size() const
94 {
95 return m_chunks.empty() ? 0 : (m_chunks.size()-1)*chunkSize +
96 m_chunks.back()->data.size();
97 }
98
99 /// adds an element to the end
100 void push_back(T &&t)
101 {
102 make_room();
103 m_chunks.back()->data.push_back(std::move(t));
104 }
105
106 /// constructs an element in-place at the end
107 template<class...Args>
108 void emplace_back(Args&&...args)
109 {
110 make_room();
111 m_chunks.back()->data.emplace_back(std::forward<Args>(args)...);
112 }
113
114 /// removes the last element
115 void pop_back()
116 {
117 m_chunks.back()->data.pop_back();
118 if (m_chunks.back()->data.size()==0) // remove chunk if empty
119 {
120 m_chunks.pop_back();
121 }
122 }
123
124 /// access specified element
125 T &at(size_t i) { return m_chunks.at(i>>chunkBits)->data.at(i&chunkMask); }
126 /// access specified element
127 const T &at(size_t i) const { return m_chunks.at(i>>chunkBits)->data.at(i&chunkMask); }
128
129 /// access the first element
130 T &front() { return m_chunks.front()->data.front(); }
131 /// access the first element
132 const T &front() const { return m_chunks.front()->data.front(); }
133
134 /// access the last element
135 T &back() { return m_chunks.back()->data.back(); }
136 /// access the last element
137 const T &back() const { return m_chunks.back()->data.back(); }
138
139 /// checks whether the container is empty
140 bool empty() const { return m_chunks.empty(); }
141
142 /// clears the contents
143 void clear() { m_chunks.clear(); }
144
145 private:
147 {
148 if (m_chunks.empty() ||
149 m_chunks.back()->data.size()==chunkSize) // add new chuck if needed
150 {
151 m_chunks.push_back(std::make_unique<Chunk>());
152 }
153 }
154 std::vector<ChunkPtr> m_chunks;
155};
156
157#endif
bidirectional iterator
Definition growvector.h:56
std::bidirectional_iterator_tag iterator_category
Definition growvector.h:58
friend bool operator!=(const Iterator &a, const Iterator &b)
Definition growvector.h:73
std::ptrdiff_t difference_type
Definition growvector.h:59
Iterator operator++(int)
Definition growvector.h:69
Iterator(C &vec, size_t pos)
Definition growvector.h:64
Iterator & operator++()
Definition growvector.h:68
Iterator operator--(int)
Definition growvector.h:71
Iterator & operator--()
Definition growvector.h:70
friend bool operator==(const Iterator &a, const Iterator &b)
Definition growvector.h:72
std::vector like container optimized for pushing elements to the back.
Definition growvector.h:40
const T & at(size_t i) const
access specified element
Definition growvector.h:127
void clear()
clears the contents
Definition growvector.h:143
void push_back(T &&t)
adds an element to the end
Definition growvector.h:100
size_t size() const
returns the number of elements
Definition growvector.h:93
iterator end()
returns an iterator to the end
Definition growvector.h:88
T & back()
access the last element
Definition growvector.h:135
const T & front() const
access the first element
Definition growvector.h:132
void make_room()
Definition growvector.h:146
Iterator< const GrowVector, const T > const_iterator
Definition growvector.h:80
static const size_t chunkSize
Definition growvector.h:43
void pop_back()
removes the last element
Definition growvector.h:115
bool empty() const
checks whether the container is empty
Definition growvector.h:140
T & at(size_t i)
access specified element
Definition growvector.h:125
const T & back() const
access the last element
Definition growvector.h:137
void emplace_back(Args &&...args)
constructs an element in-place at the end
Definition growvector.h:108
Iterator< GrowVector, T > iterator
Definition growvector.h:79
const_iterator end() const
returns an iterator to the end
Definition growvector.h:90
std::vector< ChunkPtr > m_chunks
Definition growvector.h:154
static const size_t chunkBits
Definition growvector.h:42
iterator begin()
returns an iterator to the beginning
Definition growvector.h:83
static const size_t chunkMask
Definition growvector.h:44
const_iterator begin() const
returns an iterator to the beginning
Definition growvector.h:85
T & front()
access the first element
Definition growvector.h:130
std::unique_ptr< Chunk > ChunkPtr
Definition growvector.h:50
#define DEFAULT_COPYABLE(cls)
Macro to help implementing the rule of 5 for a default copyable & movable class.
Definition construct.h:29
std::vector< T > data
Definition growvector.h:48