ZeroBuf  0.5.0
Zero-copy, zero-serialize, zero-hassle protocol buffers
Vector.h
1 
2 /* Copyright (c) 2015-2016, Human Brain Project
3  * Stefan.Eilemann@epfl.ch
4  */
5 
6 #ifndef ZEROBUF_VECTOR_H
7 #define ZEROBUF_VECTOR_H
8 
9 #include <zerobuf/DynamicSubAllocator.h> // used inline
10 #include <zerobuf/Zerobuf.h> // sfinae type
11 #include <zerobuf/json.h> // used inline
12 
13 #include <cstring> // memcmp
14 #include <stdexcept> // std::runtime_error
15 #include <typeinfo> // typeid
16 
17 namespace zerobuf
18 {
24 template <class T>
25 class Vector
26 {
27 public:
29  template <class U>
30  class Iterator : public std::iterator<std::forward_iterator_tag, U>
31  {
32  public:
33  Iterator(U& vector, const size_t index)
34  : _vector(vector)
35  , _index(index)
36  {
37  }
38 
39  bool operator==(const Iterator& rhs) const
40  {
41  return _index == rhs._index;
42  }
43  bool operator!=(const Iterator& rhs) const
44  {
45  return _index != rhs._index;
46  }
47 
48  Iterator& operator++()
49  {
50  ++_index;
51  return *this;
52  }
53 
54  const typename U::element_type& operator*() const
55  {
56  return _vector[_index];
57  }
58 
59  template <class Q = U, typename = typename std::enable_if<
60  !std::is_const<Q>::value>::type>
61  typename U::element_type& operator*()
62  {
63  return _vector[_index];
64  }
65 
66  private:
67  U& _vector;
68  size_t _index;
69  };
70 
71  using element_type = T;
74 
79  Vector(Allocator& alloc, size_t index);
80  ~Vector() {}
82  bool empty() const { return _getSize() == 0; }
84  uint64_t size() const { return _getSize() / _getElementSize<T>(); }
86  void clear();
87 
89  T* data() { return _alloc->template getDynamic<T>(_index); }
91  const T* data() const
92  {
93  return const_cast<const Allocator*>(_alloc)->template getDynamic<T>(
94  _index);
95  }
96 
98  void resize(size_t size);
99 
101  bool operator==(const Vector& rhs) const;
103  bool operator!=(const Vector& rhs) const;
104 
106  const_iterator begin() const;
107 
109  const_iterator end() const;
110 
112  iterator begin();
113 
115  iterator end();
116 
118  template <class Q = T>
119  const typename std::enable_if<!std::is_base_of<Zerobuf, Q>::value, Q>::type&
120  operator[](const size_t index) const;
121 
123  template <class Q = T>
124  typename std::enable_if<!std::is_base_of<Zerobuf, Q>::value, Q>::type&
125  operator[](const size_t index);
126 
128  template <class Q = T>
129  const typename std::enable_if<std::is_base_of<Zerobuf, Q>::value, Q>::type&
130  operator[](const size_t index) const;
131 
133  template <class Q = T>
134  typename std::enable_if<std::is_base_of<Zerobuf, Q>::value, Q>::type&
135  operator[](const size_t index);
136 
138  template <class Q = T>
139  void push_back(const typename std::enable_if<
140  !std::is_base_of<Zerobuf, Q>::value, Q>::type&);
141 
143  template <class Q = T>
144  void push_back(const typename std::enable_if<
145  std::is_base_of<Zerobuf, Q>::value, Q>::type&);
146 
148  void reset(Allocator& alloc)
149  {
150  _alloc = &alloc;
151  _zerobufs.clear();
152  }
153 
155  void compact(float) { /* NOP: elements are static and clear frees */}
156 
158  template <class Q = T>
159  void fromJSON(const Json::Value& json,
160  const typename std::enable_if<
161  std::is_base_of<Zerobuf, Q>::value, Q>::type* = nullptr);
162 
164  template <class Q = T>
165  void fromJSON(const Json::Value& json,
166  const typename std::enable_if<std::is_enum<Q>::value,
167  Q>::type* = nullptr);
168 
170  template <class Q = T>
171  void fromJSON(const Json::Value& json,
172  const typename std::enable_if<std::is_arithmetic<Q>::value,
173  Q>::type* = nullptr);
174 
176  template <class Q = T>
177  void fromJSON(
178  const Json::Value& json,
179  const typename std::enable_if<std::is_same<Q, servus::uint128_t>::value,
180  Q>::type* = nullptr);
181 
183  template <class Q = T>
184  void toJSON(
185  Json::Value& json,
186  const typename std::enable_if<std::is_base_of<Zerobuf, Q>::value,
187  Q>::type* = nullptr) const;
188 
190  template <class Q = T>
191  void toJSON(Json::Value& json,
192  const typename std::enable_if<std::is_enum<Q>::value,
193  Q>::type* = nullptr) const;
194 
196  template <class Q = T>
197  void toJSON(Json::Value& json,
198  const typename std::enable_if<std::is_arithmetic<Q>::value,
199  Q>::type* = nullptr) const;
200 
202  template <class Q = T>
203  void toJSON(
204  Json::Value& json,
205  const typename std::enable_if<std::is_same<Q, servus::uint128_t>::value,
206  Q>::type* = nullptr) const;
207 
209  template <class Q = T>
210  void fromJSONBinary(const Json::Value& json,
211  const typename std::enable_if<std::is_pod<Q>::value,
212  Q>::type* = nullptr);
213 
215  template <class Q = T>
216  void toJSONBinary(Json::Value& json,
217  const typename std::enable_if<std::is_pod<Q>::value,
218  Q>::type* = nullptr) const;
219 
220 private:
221  Allocator* _alloc;
222  const size_t _index;
223  mutable std::vector<T> _zerobufs;
224 
225  Vector() = delete;
226  Vector(const Vector& rhs) = delete;
227  Vector(const Vector&& rhs) = delete;
228 
229  size_t _getSize() const { return _alloc->getDynamicSize(_index); }
230  void copyBuffer(uint8_t* data, size_t size);
231 
232  template <class Q = T>
233  size_t _getElementSize(
234  typename std::enable_if<std::is_base_of<Zerobuf, Q>::value, Q>::type* =
235  0) const
236  {
237  return Q::ZEROBUF_STATIC_SIZE();
238  }
239 
240  template <class Q = T>
241  size_t _getElementSize(
242  typename std::enable_if<!std::is_base_of<Zerobuf, Q>::value, Q>::type* =
243  0) const
244  {
245  return sizeof(Q);
246  }
247 };
248 
249 // Implementation
250 template <class T>
251 inline Vector<T>::Vector(Allocator& alloc, const size_t index)
252  : _alloc(&alloc)
253  , _index(index)
254 {
255 }
256 
257 template <class T>
258 inline void Vector<T>::clear()
259 {
260  _alloc->updateAllocation(_index, false, 0);
261  _zerobufs.clear();
262 }
263 
264 template <class T>
265 inline void Vector<T>::resize(const size_t size_)
266 {
267  _alloc->updateAllocation(_index, true /*copy*/,
268  size_ * _getElementSize<T>());
269 }
270 
271 template <class T>
273 {
274  return const_iterator(*this, 0);
275 }
276 
277 template <class T>
279 {
280  return const_iterator(*this, size());
281 }
282 
283 template <class T>
285 {
286  return iterator(*this, 0);
287 }
288 
289 template <class T>
291 {
292  return iterator(*this, size());
293 }
294 
295 template <class T>
296 inline bool Vector<T>::operator==(const Vector& rhs) const
297 {
298  if (this == &rhs)
299  return true;
300  const size_t size_ = _getSize();
301  if (size_ != rhs._getSize())
302  return false;
303  if (size_ == 0)
304  return true;
305 
306  // memory compare is valid for Zerobufs as well since they are right now
307  // static and therefore will have the same layout
308  return ::memcmp(static_cast<const void*>(data()),
309  static_cast<const void*>(rhs.data()), size_) == 0;
310 }
311 
312 template <class T>
313 inline bool Vector<T>::operator!=(const Vector& rhs) const
314 {
315  return !(operator==(rhs));
316 }
317 
318 template <class T>
319 template <class Q>
320 inline const typename std::enable_if<!std::is_base_of<Zerobuf, Q>::value,
321  Q>::type& Vector<T>::
322  operator[](const size_t index) const
323 {
324  if (index >= size())
325  throw std::runtime_error("Vector out of bounds read");
326 
327  return data()[index];
328 }
329 
330 template <class T>
331 template <class Q>
332 inline typename std::enable_if<!std::is_base_of<Zerobuf, Q>::value, Q>::type&
333  Vector<T>::operator[](const size_t index)
334 {
335  if (index >= size())
336  throw std::runtime_error("Vector out of bounds read");
337 
338  return data()[index];
339 }
340 
341 template <class T>
342 template <class Q>
343 inline const typename std::enable_if<std::is_base_of<Zerobuf, Q>::value,
344  Q>::type& Vector<T>::
345  operator[](const size_t index) const
346 {
347  if (index >= size())
348  throw std::runtime_error("Vector out of bounds read");
349 
350  while (_zerobufs.size() < index + 1)
351  _zerobufs.emplace_back(AllocatorPtr(
352  new DynamicSubAllocator(*_alloc, _index, _zerobufs.size(),
353  _getElementSize<T>())));
354  return _zerobufs[index];
355 }
356 
357 template <class T>
358 template <class Q>
359 inline typename std::enable_if<std::is_base_of<Zerobuf, Q>::value, Q>::type&
360  Vector<T>::operator[](const size_t index)
361 {
362  if (index >= size())
363  throw std::runtime_error("Vector out of bounds read");
364 
365  while (_zerobufs.size() < index + 1)
366  _zerobufs.emplace_back(AllocatorPtr(
367  new DynamicSubAllocator(*_alloc, _index, _zerobufs.size(),
368  _getElementSize<T>())));
369  return _zerobufs[index];
370 }
371 
372 template <class T>
373 template <class Q>
374 inline void Vector<T>::push_back(
375  const typename std::enable_if<!std::is_base_of<Zerobuf, Q>::value, Q>::type&
376  value)
377 {
378  const size_t size_ = _getSize();
379  T* newPtr = reinterpret_cast<T*>(
380  _alloc->updateAllocation(_index, true /*copy*/, size_ + sizeof(T)));
381  newPtr[size_ / _getElementSize<T>()] = value;
382 }
383 
384 template <class T>
385 template <class Q>
387  const typename std::enable_if<std::is_base_of<Zerobuf, Q>::value, Q>::type&
388  value)
389 {
390  const size_t size_ = _getSize();
391  const zerobuf::Data& zerobuf = value.toBinary();
392  uint8_t* newPtr =
393  _alloc->updateAllocation(_index, true /*copy*/, size_ + zerobuf.size);
394  ::memcpy(newPtr + size_, zerobuf.ptr.get(), zerobuf.size);
395 }
396 
397 template <class T>
398 template <class Q>
400  const Json::Value& json,
401  const typename std::enable_if<std::is_base_of<Zerobuf, Q>::value, Q>::type*)
402 {
403  const size_t size_ = getJSONSize(json);
404  _alloc->updateAllocation(_index, false, size_ * _getElementSize<T>());
405  for (size_t i = 0; i < size_; ++i)
406  zerobuf::fromJSON(getJSONField(json, i), (*this)[i]);
407 }
408 
409 template <class T>
410 template <class Q>
412  const Json::Value& json,
413  const typename std::enable_if<std::is_enum<Q>::value, Q>::type*)
414 {
415  const size_t size_ = getJSONSize(json);
416  T* array = reinterpret_cast<T*>(
417  _alloc->updateAllocation(_index, false /*no copy*/, size_ * sizeof(T)));
418 
419  for (size_t i = 0; i < size_; ++i)
420  array[i] = string_to_enum<T>(
421  zerobuf::fromJSON<std::string>(getJSONField(json, i)));
422 }
423 
424 template <class T>
425 template <class Q>
427  const Json::Value& json,
428  const typename std::enable_if<std::is_arithmetic<Q>::value, Q>::type*)
429 {
430  const size_t size_ = getJSONSize(json);
431  T* array = reinterpret_cast<T*>(
432  _alloc->updateAllocation(_index, false /*no copy*/, size_ * sizeof(T)));
433 
434  for (size_t i = 0; i < size_; ++i)
435  array[i] = zerobuf::fromJSON<T>(getJSONField(json, i));
436 }
437 
438 template <class T>
439 template <class Q>
441  const Json::Value& json,
442  const typename std::enable_if<std::is_same<Q, servus::uint128_t>::value,
443  Q>::type*)
444 {
445  const size_t size_ = getJSONSize(json);
446  T* array = reinterpret_cast<T*>(
447  _alloc->updateAllocation(_index, false /*no copy*/, size_ * sizeof(T)));
448 
449  for (size_t i = 0; i < size_; ++i)
450  array[i] = zerobuf::fromJSON<T>(getJSONField(json, i));
451 }
452 
453 template <class T>
454 template <class Q>
455 inline void Vector<T>::toJSON(
456  Json::Value& json,
457  const typename std::enable_if<std::is_base_of<Zerobuf, Q>::value, Q>::type*)
458  const
459 {
460  const size_t size_ = size();
461  zerobuf::emptyJSONArray(
462  json); // return [] instead of null if array is empty
463  for (size_t i = 0; i < size_; ++i)
464  zerobuf::toJSON(static_cast<const Zerobuf&>((*this)[i]),
465  getJSONField(json, i));
466 }
467 
468 template <class T>
469 template <class Q>
470 inline void Vector<T>::toJSON(
471  Json::Value& json,
472  const typename std::enable_if<std::is_enum<Q>::value, Q>::type*) const
473 {
474  const size_t size_ = size();
475  zerobuf::emptyJSONArray(
476  json); // return [] instead of null if array is empty
477  for (size_t i = 0; i < size_; ++i)
478  zerobuf::toJSON(enum_to_string<T>((*this)[i]), getJSONField(json, i));
479 }
480 
481 template <class T>
482 template <class Q>
483 inline void Vector<T>::toJSON(
484  Json::Value& json,
485  const typename std::enable_if<std::is_arithmetic<Q>::value, Q>::type*) const
486 {
487  const size_t size_ = size();
488  zerobuf::emptyJSONArray(
489  json); // return [] instead of null if array is empty
490  for (size_t i = 0; i < size_; ++i)
491  zerobuf::toJSON((*this)[i], getJSONField(json, i));
492 }
493 
494 template <class T>
495 template <class Q>
496 inline void Vector<T>::toJSON(
497  Json::Value& json,
498  const typename std::enable_if<std::is_same<Q, servus::uint128_t>::value,
499  Q>::type*) const
500 {
501  const size_t size_ = size();
502  zerobuf::emptyJSONArray(
503  json); // return [] instead of null if array is empty
504  for (size_t i = 0; i < size_; ++i)
505  zerobuf::toJSON((*this)[i], getJSONField(json, i));
506 }
507 
508 template <class T>
509 template <class Q>
511  const Json::Value& json,
512  const typename std::enable_if<std::is_pod<Q>::value, Q>::type*)
513 {
514  const std::string& decoded = zerobuf::fromJSONBinary(json);
515  copyBuffer((uint8_t*)decoded.data(), decoded.length());
516 }
517 
518 template <class T>
519 template <class Q>
521  Json::Value& json,
522  const typename std::enable_if<std::is_pod<Q>::value, Q>::type*) const
523 {
524  zerobuf::toJSONBinary(data(), _getSize(), json);
525 }
526 
527 template <class T>
528 inline void Vector<T>::copyBuffer(uint8_t* data_, size_t size_)
529 {
530  void* to = _alloc->updateAllocation(_index, false /*no copy*/, size_);
531  ::memcpy(to, data_, size_);
532 }
533 
534 template <class T>
535 inline std::ostream& operator<<(std::ostream& os, const Vector<T>& vector)
536 {
537  return os << typeid(vector).name() << " of size " << vector.size();
538 }
539 
540 template <>
541 inline std::ostream& operator<<(std::ostream& os, const Vector<char>& string)
542 {
543  return os << string.data();
544 }
545 }
546 
547 #endif
void compact(float)
Remove unused memory from vector and all members.
Definition: Vector.h:155
const_iterator end() const
Definition: Vector.h:278
bool operator==(const Vector &rhs) const
Definition: Vector.h:296
bool empty() const
Definition: Vector.h:82
bool operator!=(const Vector &rhs) const
Definition: Vector.h:313
void fromJSON(const Json::Value &json, const typename std::enable_if< std::is_base_of< Zerobuf, Q >::value, Q >::type *=nullptr)
Update this vector of ZeroBufs from its JSON representation.
Definition: Vector.h:399
void resize(size_t size)
Resize the vector to new size; keeps elements untouched.
Definition: Vector.h:265
Zero-copy, zero-serialize, zero-hassle protocol buffers.
Definition: Allocator.h:12
const_iterator begin() const
Definition: Vector.h:272
Forward iterator for Vector< T >
Definition: Vector.h:30
const std::enable_if<!std::is_base_of< Zerobuf, Q >::value, Q >::type & operator[](const size_t index) const
Definition: Vector.h:322
const T * data() const
Definition: Vector.h:91
uint64_t size() const
Definition: Vector.h:84
void push_back(const typename std::enable_if< !std::is_base_of< Zerobuf, Q >::value, Q >::type &)
Insert a builtin element at the end of the vector.
void fromJSONBinary(const Json::Value &json, const typename std::enable_if< std::is_pod< Q >::value, Q >::type *=nullptr)
Update this vector from its JSON, base64-encoded representation.
Definition: Vector.h:510
void toJSONBinary(Json::Value &json, const typename std::enable_if< std::is_pod< Q >::value, Q >::type *=nullptr) const
Definition: Vector.h:520
Allocator base class and interface.
Definition: Allocator.h:20
void clear()
Empty the vector.
Definition: Vector.h:258
A zerobuf child allocator which manages a dynamic allocation of statically-sized members.
void toJSON(Json::Value &json, const typename std::enable_if< std::is_base_of< Zerobuf, Q >::value, Q >::type *=nullptr) const
Definition: Vector.h:455
T * data()
Definition: Vector.h:89
STL-like vector abstraction for dynamic arrays in a zerobuf.
Definition: types.h:29