BFGraph: src/TinyVector.hpp Source File

BFGraph

TinyVector.hpp
1 #ifndef KALLISTO_TINYVECTOR_H
2 #define KALLISTO_TINYVECTOR_H
3
4 #include <vector>
5 #include <algorithm>
6 #include <stdint.h>
7
8 template<class T, int N = (1 + (48 / sizeof(T)))>
9 class tiny_vector {
10
11 public:
12
13 tiny_vector() : short_(true) { arr.size = 0; }
14
15 tiny_vector(std::initializer_list<T> l) {
16
17 short_ = true;
18 arr.size = 0;
19
20 reserve(l.size());
21
22 for (auto &x : l) push_back(x);
23 }
24
25 ~tiny_vector() { clear(); }
26
27 union {
28
29 struct {
30 T data[N];
31 uint8_t size;
32 } arr;
33
34 struct {
35 T *data;
36 size_t cap;
37 size_t size; // 24 bytes + ~24 malloc overhead
38 } vec;
39 };
40
41 tiny_vector(const tiny_vector& o) {
42
43 short_ = true;
44 arr.size = 0;
45
46 reserve(o.capacity());
47
48 for (auto &x : o) push_back(x);
49
50 }
51
52 tiny_vector(const std::vector<T>& o) {
53
54 short_ = true;
55 arr.size = 0;
56
57 reserve(o.capacity());
58
59 for (auto &x : o) push_back(x);
60 }
61
62 tiny_vector(tiny_vector&& o) {
63
64 if (o.isShort()) {
65
66 const size_t sz = o.size();
67
68 for (size_t i = 0; i < sz; i++) arr.data[i] = std::move(o.arr.data[i]);
69
70 o.arr.size = 0;
71 arr.size = sz;
72 short_ = true;
73 }
74 else {
75
76 vec.data = o.vec.data;
77 vec.size = o.vec.size;
78 vec.cap = o.vec.cap;
79 o.vec.data = nullptr;
80 o.arr.size = 0;
81 o.short_ = true;
82 short_ = false;
83 }
84 }
85
86 tiny_vector& operator=(const tiny_vector& o) {
87
88 clear();
89 reserve(o.capacity());
90
91 for (auto &x : o) push_back(x);
92
93 return *this;
94 }
95
96 tiny_vector& operator=(tiny_vector&& o){
97
98 if (this != &o) {
99
100 clear();
101
102 if (o.isShort()) {
103
104 const size_t sz = o.size();
105
106 for (size_t i = 0; i < sz; i++) arr.data[i] = std::move(o.arr.data[i]);
107
108 o.arr.size = 0;
109 arr.size = sz;
110 short_ = true;
111 }
112 else {
113
114 vec.data = o.vec.data;
115 vec.size = o.vec.size;
116 vec.cap = o.vec.cap;
117 o.vec.data = nullptr;
118 o.arr.size = 0;
119 o.short_ = true;
120 short_ = false;
121 }
122 }
123
124 return *this;
125 }
126
127 bool short_;
128
129 typedef T* iterator;
130 typedef T const* const_iterator;
131
132 iterator begin() { return getPointer(); }
133 const_iterator begin() const { return getPointer(); }
134 iterator end() { return getPointer() + size(); }
135 const_iterator end() const { return (getPointer() + size()); }
136
137 inline bool isShort() const { return short_; }
138
139 inline T* getPointer() {
140
141 if (isShort()) return &arr.data[0];
142 return vec.data;
143 }
144
145 inline const T* getPointer() const {
146
147 if (isShort()) return &arr.data[0];
148 return vec.data;
149 }
150
151 inline size_t size() const {
152
153 if (isShort()) return arr.size;
154 return vec.size;
155 }
156
157 inline bool empty() const { return (size()==0); }
158
159 bool operator==(const tiny_vector& o) const {
160
161 if (size() == o.size()) {
162
163 for (auto it=begin(), oit = o.begin(); it != end(); ++it, ++oit) {
164
165 if (*it != *oit) return false;
166 }
167
168 return true;
169 }
170
171 return false;
172 }
173
174 bool operator!=(const tiny_vector& o) const {
175
176 return !operator==(o);
177 }
178
179 inline size_t capacity() const {
180
181 if (isShort()) return N;
182 return vec.cap;
183 }
184
185 T& operator[](size_t i) {
186
187 return *(begin() + i);
188 }
189
190 const T& operator[](size_t i) const {
191
192 return *(begin() + i);
193 }
194
195 void push_back(const T& value) {
196
197 if (size() >= capacity()) _reserve_and_copy(std::max((size_t) 2, 3 * size() / 2));
198
199 *(end()) = value;
200
201 if (isShort()) ++arr.size;
202 else ++vec.size;
203 }
204
205 void insert(const T& value, const size_t position) {
206
207 if (size() >= capacity()) _reserve_and_copy(std::max((size_t) 2, 3 * size() / 2));
208
209 T* data = getPointer();
210
211 memmove(&data[position + 1], &data[position], (size() - position) * sizeof(T));
212
213 data[position] = value;
214
215 if (isShort()) ++arr.size;
216 else ++vec.size;
217 }
218
219 void remove(const size_t position) {
220
221 T* data = getPointer();
222
223 if (position != size() - 1)
224 memmove(&data[position], &data[position + 1], (size() - position - 1) * sizeof(T));
225
226 if (isShort()) --arr.size;
227 else --vec.size;
228 }
229
230 void clear() {
231
232 if (!isShort()) {
233
234 delete[] vec.data;
235 vec.data = nullptr;
236 vec.size = 0;
237 vec.cap = 0;
238 }
239 else {
240
241 for (auto it = begin(); it != end(); ++it) it->~T(); // manually call destructor
242 arr.size = 0;
243 }
244
245 short_ = true;
246 }
247
248 inline void reserve(size_t sz) {
249
250 if (sz > capacity()) _reserve_and_copy(sz);
251 }
252
253 void _reserve_and_copy(size_t sz) {
254
255 if (sz <= capacity()) return;
256
257 size_t old_size = size();
258
259 T* newdata = new T[sz];
260 // move old elements over
261 size_t i = 0;
262 for (auto it = begin(); it != end(); ++it, ++i) newdata[i] = std::move(*it); //
263
264 if (!isShort()) delete[] vec.data;
265
266 short_ = false;
267 vec.size = old_size;
268 vec.cap = sz;
269 vec.data = newdata;
270 }
271 };
272
273 #endif
tiny_vector
Definition: TinyVector.hpp:9