ZeroBuf  0.3.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* >( _alloc )->template getDynamic< T >( _index ); }
50 
52  bool operator == ( const Vector& rhs ) const;
54  bool operator != ( const Vector& rhs ) const;
55 
57  template< class Q = T >
58  const typename std::enable_if<!std::is_base_of<Zerobuf,Q>::value, Q>::type&
59  operator[] ( const size_t index ) const;
60 
62  template< class Q = T >
63  typename std::enable_if< !std::is_base_of< Zerobuf, Q >::value, Q >::type&
64  operator[] ( const size_t index );
65 
67  template< class Q = T >
68  const typename std::enable_if< std::is_base_of<Zerobuf,Q>::value, Q >::type&
69  operator[] ( const size_t index ) const;
70 
72  template< class Q = T >
73  typename std::enable_if< std::is_base_of< Zerobuf, Q >::value, Q >::type&
74  operator[] ( const size_t index );
75 
77  template< class Q = T > void
78  push_back( const typename std::enable_if<
79  !std::is_base_of<Zerobuf,Q>::value, Q>::type& );
80 
82  template< class Q = T > void
83  push_back( const typename std::enable_if<
84  std::is_base_of<Zerobuf,Q>::value, Q>::type&);
85 
87  void reset( Allocator& alloc ) { _alloc = &alloc; _zerobufs.clear(); }
88 
90  void compact( float ) { /* NOP: elements are static and clear frees */ }
91 
93  template< class Q = T > void
94  fromJSON( const Json::Value& json, const typename std::enable_if<
95  std::is_base_of< Zerobuf, Q >::value, Q >::type* = nullptr );
96 
98  template< class Q = T > void
99  fromJSON( const Json::Value& json, const typename std::enable_if<
100  !std::is_base_of< Zerobuf, Q >::value, Q >::type* = nullptr );
101 
103  template< class Q = T > void
104  toJSON( Json::Value& json, const typename std::enable_if<
105  std::is_base_of< Zerobuf, Q >::value, Q >::type* = nullptr ) const;
106 
108  template< class Q = T > void
109  toJSON( Json::Value& json, const typename std::enable_if<
110  !std::is_base_of< Zerobuf, Q >::value, Q >::type* = nullptr ) const;
111 
113  template< class Q = T > void
114  fromJSONBinary( const Json::Value& json, const typename std::enable_if<
115  std::is_pod< Q >::value, Q >::type* = nullptr );
116 
118  template< class Q = T > void
119  toJSONBinary( Json::Value& json, const typename std::enable_if<
120  std::is_pod< Q >::value, Q >::type* = nullptr ) const;
121 
122 private:
123  Allocator* _alloc;
124  const size_t _index;
125  mutable std::vector< T > _zerobufs;
126 
127  Vector() = delete;
128  Vector( const Vector& rhs ) = delete;
129  Vector( const Vector&& rhs ) = delete;
130 
131  size_t _getSize() const { return _alloc->getDynamicSize( _index ); }
132  void _resize( const size_t size_ )
133  { _alloc->updateAllocation( _index, true /*copy*/, size_ ); }
134  void copyBuffer( uint8_t* data, size_t size );
135 
136  template< class Q = T > size_t _getElementSize(
137  typename std::enable_if< std::is_base_of< Zerobuf, Q >::value,
138  Q >::type* = 0 ) const
139  {
140  return Q::ZEROBUF_STATIC_SIZE();
141  }
142 
143  template< class Q = T > size_t _getElementSize(
144  typename std::enable_if< !std::is_base_of< Zerobuf, Q >::value,
145  Q >::type* = 0 ) const
146  {
147  return sizeof( Q );
148  }
149 };
150 
151 // Implementation
152 template< class T > inline
153 Vector< T >::Vector( Allocator& alloc, const size_t index )
154  : _alloc( &alloc )
155  , _index( index )
156 {}
157 
158 template< class T > inline void Vector< T >::clear()
159 {
160  _alloc->updateAllocation( _index, false, 0 );
161  _zerobufs.clear();
162 }
163 
164 template< class T > inline
165 bool Vector< T >::operator == ( const Vector& rhs ) const
166 {
167  if( this == &rhs )
168  return true;
169  const size_t size_ = _getSize();
170  if( size_ != rhs._getSize( ))
171  return false;
172  if( size_ == 0 )
173  return true;
174 
175  // memory compare is valid for Zerobufs as well since they are right now
176  // static and therefore will have the same layout
177  return ::memcmp( static_cast< const void* >( data( )),
178  static_cast< const void* >( rhs.data( )), size_ ) == 0;
179 }
180 
181 template< class T > inline
182 bool Vector< T >::operator != ( const Vector& rhs ) const
183 {
184  return !(operator == ( rhs ));
185 }
186 
187 template< class T > template< class Q > inline const typename
188 std::enable_if<!std::is_base_of<Zerobuf,Q>::value, Q>::type&
189 Vector< T >::operator[] ( const size_t index ) const
190 {
191  if( index >= size( ))
192  throw std::runtime_error( "Vector out of bounds read" );
193 
194  return data()[ index ];
195 }
196 
197 template< class T > template< class Q > inline typename
198 std::enable_if< !std::is_base_of< Zerobuf, Q >::value, Q >::type&
199 Vector< T >::operator[] ( const size_t index )
200 {
201  if( index >= size( ))
202  throw std::runtime_error( "Vector out of bounds read" );
203 
204  return data()[ index ];
205 }
206 
207 template< class T > template< class Q > inline const typename
208 std::enable_if< std::is_base_of<Zerobuf,Q>::value, Q >::type&
209 Vector< T >::operator[] ( const size_t index ) const
210 {
211  if( index >= size( ))
212  throw std::runtime_error( "Vector out of bounds read" );
213 
214  while( _zerobufs.size() < index + 1 )
215  _zerobufs.emplace_back( AllocatorPtr(
216  new ConstDynamicSubAllocator( *_alloc, _index, _zerobufs.size(),
217  _getElementSize< T >( ))));
218  return _zerobufs[ index ];
219 }
220 
221 template< class T > template< class Q > inline typename
222 std::enable_if< std::is_base_of< Zerobuf, Q >::value, Q >::type&
223 Vector< T >::operator[] ( const size_t index )
224 {
225  if( index >= size( ))
226  throw std::runtime_error( "Vector out of bounds read" );
227 
228  while( _zerobufs.size() < index + 1 )
229  _zerobufs.emplace_back( AllocatorPtr(
230  new DynamicSubAllocator( *_alloc, _index, _zerobufs.size(),
231  _getElementSize< T >( ))));
232  return _zerobufs[ index ];
233 }
234 
235 template< class T > template< class Q > inline void
237  const typename std::enable_if<!std::is_base_of<Zerobuf,Q>::value, Q>::type&
238  value )
239 {
240  const size_t size_ = _getSize();
241  T* newPtr = reinterpret_cast< T* >(
242  _alloc->updateAllocation( _index, true /*copy*/, size_ + sizeof( T )));
243  newPtr[ size_ / _getElementSize< T >() ] = value;
244 }
245 
246 template< class T > template< class Q > inline void
248  const typename std::enable_if<std::is_base_of<Zerobuf,Q>::value, Q>::type&
249  value )
250 {
251  const size_t size_ = _getSize();
252  const zerobuf::Data& zerobuf = value.toBinary();
253  uint8_t* newPtr = _alloc->updateAllocation( _index, true /*copy*/,
254  size_ + zerobuf.size );
255  ::memcpy( newPtr + size_, zerobuf.ptr.get(), zerobuf.size );
256 }
257 
258 template< class T > template< class Q > inline
259 void Vector< T >::fromJSON( const Json::Value& json,
260  const typename std::enable_if<std::is_base_of<Zerobuf,Q>::value, Q>::type* )
261 {
262  const size_t size_ = getJSONSize( json );
263  _alloc->updateAllocation( _index, false, size_ * _getElementSize< T >( ));
264  for( size_t i = 0; i < size_; ++i )
265  zerobuf::fromJSON( getJSONField( json, i ), (*this)[i] );
266 }
267 
268 template< class T > template< class Q > inline
269 void Vector< T >::fromJSON( const Json::Value& json,
270  const typename std::enable_if<!std::is_base_of<Zerobuf,Q>::value, Q>::type*)
271 {
272  const size_t size_ = getJSONSize( json );
273  T* array = reinterpret_cast< T* >(
274  _alloc->updateAllocation( _index, false /*no copy*/, size_*sizeof( T)));
275 
276  for( size_t i = 0; i < size_; ++i )
277  array[i] = zerobuf::fromJSON< T >( getJSONField( json, i ));
278 }
279 
280 template< class T > template< class Q > inline void
281 Vector< T >::toJSON( Json::Value& json, const typename std::enable_if<
282  std::is_base_of< Zerobuf, Q >::value, Q >::type* ) const
283 {
284  const size_t size_ = size();
285  for( size_t i = 0; i < size_; ++i )
286  zerobuf::toJSON( static_cast< const Zerobuf& >(( *this )[ i ]),
287  getJSONField( json, i ));
288 }
289 
290 template< class T > template< class Q > inline void
291 Vector< T >::toJSON( Json::Value& json, const typename std::enable_if<
292  !std::is_base_of< Zerobuf, Q >::value, Q >::type* ) const
293 {
294  const size_t size_ = size();
295  for( size_t i = 0; i < size_; ++i )
296  zerobuf::toJSON( (*this)[i], getJSONField( json, i ));
297 }
298 
299 template< class T > template< class Q > inline void
300 Vector< T >::fromJSONBinary( const Json::Value& json,
301  const typename std::enable_if< std::is_pod< Q >::value, Q >::type* )
302 {
303  const std::string& decoded = zerobuf::fromJSONBinary( json );
304  copyBuffer( (uint8_t*)decoded.data(), decoded.length( ));
305 }
306 
307 template< class T > template< class Q > inline void
308 Vector< T >::toJSONBinary( Json::Value& json,
309  const typename std::enable_if< std::is_pod< Q >::value, Q >::type* ) const
310 {
311  zerobuf::toJSONBinary( data(), _getSize(), json );
312 }
313 
314 template< class T > inline
315 void Vector< T >::copyBuffer( uint8_t* data_, size_t size_ )
316 {
317  void* to = _alloc->updateAllocation( _index, false /*no copy*/, size_ );
318  ::memcpy( to, data_, size_ );
319 }
320 
321 template< class T > inline
322 std::ostream& operator << ( std::ostream& os, const Vector< T >& vector )
323 {
324  return os << typeid( vector ).name() << " of size " << vector.size();
325 }
326 
327 template<> inline
328 std::ostream& operator << ( std::ostream& os, const Vector< char >& string )
329 {
330  return os << string.data();
331 }
332 
333 }
334 
335 #endif
void compact(float)
Remove unused memory from vector and all members.
Definition: Vector.h:90
bool operator==(const Vector &rhs) const
Definition: Vector.h:165
bool empty() const
Definition: Vector.h:36
bool operator!=(const Vector &rhs) const
Definition: Vector.h:182
void fromJSON(const Json::Value &json, const typename std::enable_if< std::is_base_of< Zerobuf, Q >::value, Q >::type *=nullptr)
Update this vector from its JSON representation.
Definition: Vector.h:259
Zero-copy, zero-serialize, zero-hassle protocol buffers.
Definition: Allocator.h:12
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:300
void toJSONBinary(Json::Value &json, const typename std::enable_if< std::is_pod< Q >::value, Q >::type *=nullptr) const
Definition: Vector.h:308
Allocator base class and interface.
Definition: Allocator.h:20
void clear()
Empty the vector.
Definition: Vector.h:158
const std::enable_if<!std::is_base_of< Zerobuf, Q >::value, Q >::type & operator[](const size_t index) const
void toJSON(Json::Value &json, const typename std::enable_if< std::is_base_of< Zerobuf, Q >::value, Q >::type *=nullptr) const
Definition: Vector.h:281
T * data()
Definition: Vector.h:45
STL-like vector abstraction for dynamic arrays in a zerobuf.
Definition: types.h:28