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 
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
Definition: TinyVector.hpp:9