ZeroBuf  0.4.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:
32  Vector( Allocator& alloc, size_t index );
33  ~Vector() {}
34 
36  bool empty() const { return _getSize() == 0; }
37 
39  uint64_t size() const { return _getSize() / _getElementSize< T >(); }
40 
42  void clear();
43 
45  T* data() { return _alloc->template getDynamic< T >( _index ); }
46 
48  const T* data() const
49  { return const_cast< const Allocator* >
50  ( _alloc )->template getDynamic< T >( _index ); }
51 
53  bool operator == ( const Vector& rhs ) const;
55  bool operator != ( const Vector& rhs ) const;
56 
58  template< class Q = T >
59  const typename std::enable_if<!std::is_base_of<Zerobuf,Q>::value, Q>::type&
60  operator[] ( const size_t index ) const;
61 
63  template< class Q = T >
64  typename std::enable_if< !std::is_base_of< Zerobuf, Q >::value, Q >::type&
65  operator[] ( const size_t index );
66 
68  template< class Q = T >
69  const typename std::enable_if< std::is_base_of<Zerobuf,Q>::value, Q >::type&
70  operator[] ( const size_t index ) const;
71 
73  template< class Q = T >
74  typename std::enable_if< std::is_base_of< Zerobuf, Q >::value, Q >::type&
75  operator[] ( const size_t index );
76 
78  template< class Q = T > void
79  push_back( const typename std::enable_if<
80  !std::is_base_of<Zerobuf,Q>::value, Q>::type& );
81 
83  template< class Q = T > void
84  push_back( const typename std::enable_if<
85  std::is_base_of<Zerobuf,Q>::value, Q>::type& );
86 
88  void reset( Allocator& alloc ) { _alloc = &alloc; _zerobufs.clear(); }
89 
91  void compact( float ) { /* NOP: elements are static and clear frees */ }
92 
94  template< class Q = T > void
95  fromJSON( const Json::Value& json, const typename std::enable_if<
96  std::is_base_of< Zerobuf, Q >::value, Q >::type* = nullptr );
97 
99  template< class Q = T > void
100  fromJSON( const Json::Value& json, const typename std::enable_if<
101  std::is_enum< Q >::value, Q >::type* = nullptr );
102 
104  template< class Q = T > void
105  fromJSON( const Json::Value& json, const typename std::enable_if<
106  std::is_arithmetic< Q >::value, Q >::type* = nullptr );
107 
109  template< class Q = T > void
110  fromJSON( const Json::Value& json, const typename std::enable_if<
111  std::is_same< Q, servus::uint128_t >::value, Q >::type* = nullptr );
112 
114  template< class Q = T > void
115  toJSON( Json::Value& json, const typename std::enable_if<
116  std::is_base_of< Zerobuf, Q >::value, Q >::type* = nullptr ) const;
117 
119  template< class Q = T > void
120  toJSON( Json::Value& json, const typename std::enable_if<
121  std::is_enum< Q >::value, Q >::type* = nullptr ) const;
122 
124  template< class Q = T > void
125  toJSON( Json::Value& json, const typename std::enable_if<
126  std::is_arithmetic< Q >::value, Q >::type* = nullptr ) const;
127 
129  template< class Q = T > void
130  toJSON( Json::Value& json, const typename std::enable_if<
131  std::is_same< Q, servus::uint128_t >::value, Q >::type* = nullptr ) const;
132 
134  template< class Q = T > void
135  fromJSONBinary( const Json::Value& json, const typename std::enable_if<
136  std::is_pod< Q >::value, Q >::type* = nullptr );
137 
139  template< class Q = T > void
140  toJSONBinary( Json::Value& json, const typename std::enable_if<
141  std::is_pod< Q >::value, Q >::type* = nullptr ) const;
142 
143 private:
144  Allocator* _alloc;
145  const size_t _index;
146  mutable std::vector< T > _zerobufs;
147 
148  Vector() = delete;
149  Vector( const Vector& rhs ) = delete;
150  Vector( const Vector&& rhs ) = delete;
151 
152  size_t _getSize() const { return _alloc->getDynamicSize( _index ); }
153  void _resize( const size_t size_ )
154  { _alloc->updateAllocation( _index, true /*copy*/, size_ ); }
155  void copyBuffer( uint8_t* data, size_t size );
156 
157  template< class Q = T > size_t _getElementSize(
158  typename std::enable_if< std::is_base_of< Zerobuf, Q >::value,
159  Q >::type* = 0 ) const
160  {
161  return Q::ZEROBUF_STATIC_SIZE();
162  }
163 
164  template< class Q = T > size_t _getElementSize(
165  typename std::enable_if< !std::is_base_of< Zerobuf, Q >::value,
166  Q >::type* = 0 ) const
167  {
168  return sizeof( Q );
169  }
170 };
171 
172 // Implementation
173 template< class T > inline
174 Vector< T >::Vector( Allocator& alloc, const size_t index )
175  : _alloc( &alloc )
176  , _index( index )
177 {}
178 
179 template< class T > inline void Vector< T >::clear()
180 {
181  _alloc->updateAllocation( _index, false, 0 );
182  _zerobufs.clear();
183 }
184 
185 template< class T > inline
186 bool Vector< T >::operator == ( const Vector& rhs ) const
187 {
188  if( this == &rhs )
189  return true;
190  const size_t size_ = _getSize();
191  if( size_ != rhs._getSize( ))
192  return false;
193  if( size_ == 0 )
194  return true;
195 
196  // memory compare is valid for Zerobufs as well since they are right now
197  // static and therefore will have the same layout
198  return ::memcmp( static_cast< const void* >( data( )),
199  static_cast< const void* >( rhs.data( )), size_ ) == 0;
200 }
201 
202 template< class T > inline
203 bool Vector< T >::operator != ( const Vector& rhs ) const
204 {
205  return !(operator == ( rhs ));
206 }
207 
208 template< class T > template< class Q > inline const typename
209 std::enable_if<!std::is_base_of<Zerobuf,Q>::value, Q>::type&
210 Vector< T >::operator[] ( const size_t index ) const
211 {
212  if( index >= size( ))
213  throw std::runtime_error( "Vector out of bounds read" );
214 
215  return data()[ index ];
216 }
217 
218 template< class T > template< class Q > inline typename
219 std::enable_if< !std::is_base_of< Zerobuf, Q >::value, Q >::type&
220 Vector< T >::operator[] ( const size_t index )
221 {
222  if( index >= size( ))
223  throw std::runtime_error( "Vector out of bounds read" );
224 
225  return data()[ index ];
226 }
227 
228 template< class T > template< class Q > inline const typename
229 std::enable_if< std::is_base_of<Zerobuf,Q>::value, Q >::type&
230 Vector< T >::operator[] ( const size_t index ) const
231 {
232  if( index >= size( ))
233  throw std::runtime_error( "Vector out of bounds read" );
234 
235  while( _zerobufs.size() < index + 1 )
236  _zerobufs.emplace_back( AllocatorPtr(
237  new DynamicSubAllocator( *_alloc, _index, _zerobufs.size(),
238  _getElementSize< T >( ))));
239  return _zerobufs[ index ];
240 }
241 
242 template< class T > template< class Q > inline typename
243 std::enable_if< std::is_base_of< Zerobuf, Q >::value, Q >::type&
244 Vector< T >::operator[] ( const size_t index )
245 {
246  if( index >= size( ))
247  throw std::runtime_error( "Vector out of bounds read" );
248 
249  while( _zerobufs.size() < index + 1 )
250  _zerobufs.emplace_back( AllocatorPtr(
251  new DynamicSubAllocator( *_alloc, _index, _zerobufs.size(),
252  _getElementSize< T >( ))));
253  return _zerobufs[ index ];
254 }
255 
256 template< class T > template< class Q > inline void
258  const typename std::enable_if<!std::is_base_of<Zerobuf,Q>::value, Q>::type&
259  value )
260 {
261  const size_t size_ = _getSize();
262  T* newPtr = reinterpret_cast< T* >(
263  _alloc->updateAllocation( _index, true /*copy*/, size_ + sizeof( T )));
264  newPtr[ size_ / _getElementSize< T >() ] = value;
265 }
266 
267 template< class T > template< class Q > inline void
269  const typename std::enable_if<std::is_base_of<Zerobuf,Q>::value, Q>::type&
270  value )
271 {
272  const size_t size_ = _getSize();
273  const zerobuf::Data& zerobuf = value.toBinary();
274  uint8_t* newPtr = _alloc->updateAllocation( _index, true /*copy*/,
275  size_ + zerobuf.size );
276  ::memcpy( newPtr + size_, zerobuf.ptr.get(), zerobuf.size );
277 }
278 
279 template< class T > template< class Q > inline
280 void Vector< T >::fromJSON( const Json::Value& json,
281  const typename std::enable_if<std::is_base_of<Zerobuf,Q>::value, Q>::type* )
282 {
283  const size_t size_ = getJSONSize( json );
284  _alloc->updateAllocation( _index, false, size_ * _getElementSize< T >( ));
285  for( size_t i = 0; i < size_; ++i )
286  zerobuf::fromJSON( getJSONField( json, i ), (*this)[i] );
287 }
288 
289 template< class T > template< class Q > inline
290 void Vector< T >::fromJSON( const Json::Value& json,
291  const typename std::enable_if<std::is_enum< Q>::value, Q>::type*)
292 {
293  const size_t size_ = getJSONSize( json );
294  T* array = reinterpret_cast< T* >(
295  _alloc->updateAllocation( _index, false /*no copy*/, size_*sizeof( T)));
296 
297  for( size_t i = 0; i < size_; ++i )
298  array[i] = string_to_enum< T >( zerobuf::fromJSON< std::string >
299  ( getJSONField( json, i )));
300 }
301 
302 template< class T > template< class Q > inline
303 void Vector< T >::fromJSON( const Json::Value& json,
304  const typename std::enable_if<std::is_arithmetic< Q>::value, Q>::type*)
305 {
306  const size_t size_ = getJSONSize( json );
307  T* array = reinterpret_cast< T* >(
308  _alloc->updateAllocation( _index, false /*no copy*/, size_*sizeof( T)));
309 
310  for( size_t i = 0; i < size_; ++i )
311  array[i] = zerobuf::fromJSON< T >( getJSONField( json, i ));
312 }
313 
314 template< class T > template< class Q > inline
315 void Vector< T >::fromJSON( const Json::Value& json,
316  const typename std::enable_if< std::is_same< Q,
317  servus::uint128_t >::value, Q>::type*)
318 {
319  const size_t size_ = getJSONSize( json );
320  T* array = reinterpret_cast< T* >(
321  _alloc->updateAllocation( _index, false /*no copy*/, size_*sizeof( T)));
322 
323  for( size_t i = 0; i < size_; ++i )
324  array[i] = zerobuf::fromJSON< T >( getJSONField( json, i ));
325 }
326 
327 template< class T > template< class Q > inline void
328 Vector< T >::toJSON( Json::Value& json, const typename std::enable_if<
329  std::is_base_of< Zerobuf, Q >::value, Q >::type* ) const
330 {
331  const size_t size_ = size();
332  zerobuf::emptyJSONArray( json ); // return [] instead of null if array is empty
333  for( size_t i = 0; i < size_; ++i )
334  zerobuf::toJSON( static_cast< const Zerobuf& >(( *this )[ i ]),
335  getJSONField( json, i ));
336 }
337 
338 template< class T > template< class Q > inline void
339 Vector< T >::toJSON( Json::Value& json, const typename std::enable_if<
340  std::is_enum< Q >::value, Q >::type* ) const
341 {
342  const size_t size_ = size();
343  zerobuf::emptyJSONArray( json ); // return [] instead of null if array is empty
344  for( size_t i = 0; i < size_; ++i )
345  zerobuf::toJSON( enum_to_string< T >( (*this)[i] ),
346  getJSONField( json, i ));
347 }
348 
349 template< class T > template< class Q > inline void
350 Vector< T >::toJSON( Json::Value& json, const typename std::enable_if<
351  std::is_arithmetic< Q >::value, Q >::type* ) const
352 {
353  const size_t size_ = size();
354  zerobuf::emptyJSONArray( json ); // return [] instead of null if array is empty
355  for( size_t i = 0; i < size_; ++i )
356  zerobuf::toJSON( (*this)[i], getJSONField( json, i ));
357 }
358 
359 template< class T > template< class Q > inline void
360 Vector< T >::toJSON( Json::Value& json, const typename std::enable_if<
361  std::is_same< Q, servus::uint128_t >::value, Q >::type* ) const
362 {
363  const size_t size_ = size();
364  zerobuf::emptyJSONArray( json ); // return [] instead of null if array is empty
365  for( size_t i = 0; i < size_; ++i )
366  zerobuf::toJSON( (*this)[i], getJSONField( json, i ));
367 }
368 
369 template< class T > template< class Q > inline void
370 Vector< T >::fromJSONBinary( const Json::Value& json,
371  const typename std::enable_if< std::is_pod< Q >::value, Q >::type* )
372 {
373  const std::string& decoded = zerobuf::fromJSONBinary( json );
374  copyBuffer( (uint8_t*)decoded.data(), decoded.length( ));
375 }
376 
377 template< class T > template< class Q > inline void
378 Vector< T >::toJSONBinary( Json::Value& json,
379  const typename std::enable_if< std::is_pod< Q >::value, Q >::type* ) const
380 {
381  zerobuf::toJSONBinary( data(), _getSize(), json );
382 }
383 
384 template< class T > inline
385 void Vector< T >::copyBuffer( uint8_t* data_, size_t size_ )
386 {
387  void* to = _alloc->updateAllocation( _index, false /*no copy*/, size_ );
388  ::memcpy( to, data_, size_ );
389 }
390 
391 template< class T > inline
392 std::ostream& operator << ( std::ostream& os, const Vector< T >& vector )
393 {
394  return os << typeid( vector ).name() << " of size " << vector.size();
395 }
396 
397 template<> inline
398 std::ostream& operator << ( std::ostream& os, const Vector< char >& string )
399 {
400  return os << string.data();
401 }
402 
403 }
404 
405 #endif
void compact(float)
Remove unused memory from vector and all members.
Definition: Vector.h:91
bool operator==(const Vector &rhs) const
Definition: Vector.h:186
bool empty() const
Definition: Vector.h:36
bool operator!=(const Vector &rhs) const
Definition: Vector.h:203
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:280
Zero-copy, zero-serialize, zero-hassle protocol buffers.
Definition: Allocator.h:12
const std::enable_if<!std::is_base_of< Zerobuf, Q >::value, Q >::type & operator[](const size_t index) const
Definition: Vector.h:210
const T * data() const
Definition: Vector.h:48
virtual uint8_t * updateAllocation(size_t, bool, size_t)
Update allocation of the dynamic elem at index to have newSize bytes.
Definition: Allocator.h:43
uint64_t size() const
Definition: Vector.h:39
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:370
void toJSONBinary(Json::Value &json, const typename std::enable_if< std::is_pod< Q >::value, Q >::type *=nullptr) const
Definition: Vector.h:378
Allocator base class and interface.
Definition: Allocator.h:20
void clear()
Empty the vector.
Definition: Vector.h:179
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:328
T * data()
Definition: Vector.h:45
STL-like vector abstraction for dynamic arrays in a zerobuf.
Definition: types.h:28