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