Alchemy  1.0
A framework to robustly process network messages and structured data
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pack_array.h
Go to the documentation of this file.
1 /// @file detail/pack_array.h
2 ///
3 /// The implementation to pack a fixed-size array into a Hg Message buffer.
4 ///
5 /// The MIT License(MIT)
6 /// @copyright 2014 Paul M Watt
7 // ****************************************************************************
8 #ifndef PACK_ARRAY_H_INCLUDED
9 #define PACK_ARRAY_H_INCLUDED
10 // Private Usage Include Guard ************************************************
11 // Only allow this header file to be included through pack_message.h
12 #ifndef PACK_MESSAGE_H_INCLUDED
13 # error Do not include this file directly. Use <detail/pack_message.h> instead
14 #endif
15 
16 namespace Hg
17 {
18 
19 namespace detail
20 {
21 // Forward Declarations *******************************************************
22 // ****************************************************************************
23 template< typename ValueT,
24  typename BufferT
25  >
26 size_t SerializeInBulk( ValueT &value,
27  BufferT &buffer,
28  size_t offset);
29 
30 // ****************************************************************************
31 template< class T,
32  size_t N,
33  class BufferT
34  >
35 size_t SerializeByItem( std::array<T,N> &value,
36  BufferT &buffer,
37  size_t offset);
38 
39 // ****************************************************************************
40 // Adapter function to simplify serializing a buffer from a vector-field.
41 //
42 template< class T,
43  class A,
44  class BufferT,
45  template <class, class> class VectorT
46  >
47 size_t SerializeVector (VectorT<T, A> &value,
48  BufferT &buffer,
49  size_t offset);
50 
51 namespace Array
52 {
53 
54 
55 // ****************************************************************************
56 // Exports data from the vector for fixed-size POD types.
57 //
58 template< typename ArrayT,
59  typename BufferT,
60  typename SerializerTraitT
61  >
62 struct Serializer
63 {
64  typedef ArrayT array_type;
65 
66  typedef typename
67  array_type::value_type value_type;
68 
69  typedef BufferT buffer_type;
70 
71  typedef SerializerTraitT data_type_trait;
72 
73  // **************************************************************************
74  template <typename TraitT>
75  size_t WriteMany( array_type &value,
76  buffer_type &buffer,
77  size_t offset)
78  {
79  // Calculate the size of data to write in bytes.
80  size_t size = value.size() * sizeof(value_type);
81 
82  const value_type *pFirst = &value[0];
83  const value_type *pLast = pFirst;
84 
85  std::advance(pLast, size);
86  buffer.set_range( pFirst,
87  pLast,
88  offset);
89 
90  return size;
91  }
92 
93 
94  // **************************************************************************
95  size_t Write( value_type &value,
96  buffer_type &buffer,
97  size_t offset)
98  {
99  buffer.set_data( value, offset);
100  return sizeof(value_type);
101  }
102 
103 };
104 
105 
106 // ****************************************************************************
107 // Exports arrays of bit-field values into a packed buffer.
108 //
109 template< typename T,
110  size_t N,
111  typename BufferT
112  >
113 struct Serializer <Hg::BitFieldArray<T,N>, BufferT, packed_trait>
114 {
115  typedef Hg::BitFieldArray<T,N> array_type;
116 
117  typedef typename
118  array_type::value_type value_type;
119 
120  typedef BufferT buffer_type;
121 
122  typedef packed_trait data_type_trait;
123 
124  // **************************************************************************
125  template <typename TraitT>
126  size_t WriteMany( array_type &value,
127  buffer_type &buffer,
128  size_t offset)
129  {
130  // Calculate the size of data to write in bytes.
131  size_t size = value.size() * sizeof(value_type);
132 
133  const value_type *pFirst = value.data();
134  const value_type *pLast = pFirst;
135 
136  std::advance(pLast, size);
137  buffer.set_range( pFirst,
138  pLast,
139  offset);
140 
141  return size;
142  }
143 
144 
145  // **************************************************************************
146  size_t Write( value_type &value,
147  buffer_type &buffer,
148  size_t offset)
149  {
150  buffer.set_data( value, offset);
151  return sizeof(value_type);
152  }
153 
154 };
155 
156 
157 // ****************************************************************************
158 // Exports a nested_trait with each sub-item written individually.
159 //
160 template< typename T,
161  size_t N,
162  typename BufferT
163  >
164 struct Serializer <std::array<T,N>, BufferT, nested_trait>
165 {
166  typedef typename
167  T::format_type format_type;
168 
169  typedef std::array<T,N> array_type;
170 
171  typedef typename
172  array_type::value_type value_type;
173 
174  typedef BufferT buffer_type;
175 
176  typedef nested_trait data_type_trait;
177 
178  // **************************************************************************
179  template <typename TraitT>
180  size_t WriteMany( array_type &value,
181  buffer_type &buffer,
182  size_t offset)
183  {
184  // An important typedef for selecting the proper
185  // version of the unpack function for the sub-elements.
186  typedef typename
187  message_size_trait<format_type>::type size_trait;
188 
189  size_t bytes_written = 0;
190 
191  // Process each item individually.
192  for (size_t index = 0; index < N; ++index)
193  {
194  // The offset for each item progressively increases
195  // by the number of bytes read from the input buffer.
196  size_t item_offset = offset + bytes_written;
197 
198  size_t write_len =
199  pack_message< value_type,
200  buffer_type,
201  size_trait
202  >(value[index], buffer, item_offset);
203 
204  bytes_written += write_len;
205  }
206 
207  return bytes_written;
208  }
209 };
210 
211 
212 
213 // ****************************************************************************
214 // Exports an array with each sub-item written individually.
215 //
216 template< typename T,
217  size_t N,
218  typename BufferT
219  >
220 struct Serializer <std::array<T,N>, BufferT, array_trait>
221 {
222  typedef std::array<T,N> array_type;
223 
224  typedef typename
225  array_type::value_type value_type;
226 
227  typedef BufferT buffer_type;
228 
229  // The next step discriminates on the value_type managed
230  // by the vector to select the most efficient and correct
231  // method of serializing the data.
232  typedef typename
234  < value_type >::type data_type_trait;
235 
236  // **************************************************************************
237  template <typename TraitT>
238  size_t WriteMany( array_type &value,
239  buffer_type &buffer,
240  size_t offset)
241  {
242  return SerializeInBulk(value, buffer, offset);
243  }
244 
245  // **************************************************************************
246  size_t Write( value_type &value,
247  buffer_type &buffer,
248  size_t offset)
249  {
250  return SerializeByItem(value, buffer, offset);
251  }
252 };
253 
254 // ****************************************************************************
255 // Exports an array with each sub-item written individually.
256 //
257 template< typename T,
258  size_t N,
259  typename BufferT
260  >
261 struct Serializer <std::array<T,N>, BufferT, vector_trait>
262 {
263  typedef std::array<T,N> array_type;
264 
265  typedef typename
266  array_type::value_type value_type;
267 
268  typedef BufferT buffer_type;
269 
270  // The next step discriminates on the value_type managed
271  // by the vector to select the most efficient and correct
272  // method of serializing the data.
273  typedef typename
275  < value_type >::type data_type_trait;
276 
277  // **************************************************************************
278  template <typename TraitT>
279  size_t WriteMany( array_type &value,
280  buffer_type &buffer,
281  size_t offset)
282  {
283  return SerializeByItem(value, buffer, offset);
284  }
285 
286  // **************************************************************************
287  size_t Write( value_type &value,
288  buffer_type &buffer,
289  size_t offset)
290  {
291  typedef typename
292  value_type::value_type data_type;
293 
294  typedef typename
295  value_type::allocator_type allocator_type;
296 
297  // Since this is the vector handler,
298  // all single value entries passed in will
299  // be vectors themselves.
300  size_t bytes_written =
301  SerializeVector < data_type,
302  allocator_type,
303  buffer_type
304  >(value,
305  buffer,
306  offset);
307 
308  return bytes_written;
309  }
310 };
311 
312 
313 
314 } // namespace Array
315 
316 // **************************************************************************
317 // This version writes all of the items to the buffer at once.
318 //
319 template< typename ValueT,
320  typename BufferT
321  >
322 size_t SerializeInBulk( ValueT &value,
323  BufferT &buffer,
324  size_t offset)
325 {
326  typedef ValueT array_type;
327 
328  typedef typename
329  array_type::value_type data_type;
330 
331  // The next step discriminates on the value_type managed
332  // by the vector to select the most efficient and correct
333  // method of serializing the data.
334  typedef typename
336  < data_type >::type data_type_trait;
337 
338  Array::Serializer < array_type,
339  BufferT,
340  data_type_trait> serializer;
341 
342  size_t bytes_written = 0;
343 
344  // Process each item individually.
345  for (size_t index = 0; index < value.size(); ++index)
346  {
347  // The offset for each item progressively increases
348  // by the number of bytes read from the input buffer.
349  size_t item_offset = offset + bytes_written;
350 
351  // Export sub-values one item at a time.
352  size_t write_len =
353  serializer.Write( value[index],
354  buffer,
355  item_offset);
356 
357  bytes_written += write_len;
358  }
359 
360  return bytes_written;
361 }
362 
363 
364 // **************************************************************************
365 // This version writes each item from the raw buffer individually.
366 // These fields may be because they are distinct fields of a nested definition,
367 // or variable length items.
368 //
369 // ValueT Must be a type that contains a sub-type defined as value_type.
370 // Such as std::vector or std::array
371 //
372 template< class T,
373  size_t N,
374  class BufferT
375  >
376 size_t SerializeByItem( std::array<T,N> &value,
377  BufferT &buffer,
378  size_t offset)
379 {
380  typedef std::array<T,N> array_type;
381 
382  typedef typename
383  array_type::value_type data_type;
384 
385  // The next step discriminates on the value_type managed
386  // by the vector to select the most efficient and correct
387  // method of serializing the data.
388  typedef typename
390  < data_type >::type data_type_trait;
391 
392  Array::Serializer < array_type,
393  BufferT,
394  data_type_trait> serializer;
395 
396  size_t bytes_written = 0;
397 
398  // Process each item individually.
399  for (size_t index = 0; index < N; ++index)
400  {
401  // The offset for each item progressively increases
402  // by the number of bytes read from the input buffer.
403  size_t item_offset = offset + bytes_written;
404 
405  // Export sub-values one item at a time.
406  size_t write_len =
407  serializer.Write( value[index],
408  buffer,
409  item_offset);
410 
411  bytes_written += write_len;
412  }
413 
414  return bytes_written;
415 }
416 
417 // ****************************************************************************
418 // Adapter function to simplify serializing a buffer from a vector-field.
419 //
420 template< typename T,
421  size_t N,
422  typename BufferT,
423  template <typename, size_t> class ArrayT
424  >
425 size_t SerializeArray(ArrayT<T,N> &value,
426  BufferT &buffer,
427  size_t offset)
428 {
429  // The next step discriminates on the value_type managed
430  // by the vector to select the most efficient and correct
431  // method of serializing the data.
432  typedef ArrayT<T,N> array_type;
433 
434  typedef T value_type;
435 
436  typedef typename
438  < value_type >::type value_type_trait;
439 
440  // Define the correct type of serialize functor
441  // based on the type contained within the array.
442  typedef Array::Serializer < array_type,
443  BufferT,
444  value_type_trait
445  > serializer_t;
446  typedef typename
447  serializer_t::data_type_trait data_type_trait;
448 
449  serializer_t serializer;
450  return serializer.template WriteMany<data_type_trait>(value, buffer, offset);
451 }
452 
453 // ****************************************************************************
454 // A specialized functor to write a vector type.
455 //
456 // @tparam T [typename] The value_type for this specialization
457 // is actually a format_type for the dyanmically sized vectors.
458 //
459 // @return Returns the item after the last element written by this call.
460 //
461 template< size_t IdxT,
462  typename MsgT,
463  typename BufferT
464  >
465 struct PackDatum< IdxT,
466  MsgT,
467  BufferT,
468  array_trait>
469 {
470  // Typedefs *****************************************************************
471  typedef typename
473  < IdxT,
474  typename MsgT::format_type
475  >::type proxy_type;
476 
477  typedef typename
478  proxy_type::value_type value_type;
479  typedef typename
480  value_type::value_type data_type;
481 
482  typedef MsgT message_type;
483 
484  typedef BufferT buffer_type;
485 
486 
487  // **************************************************************************
488  // Writes a fixed-size field of items to the specified buffer.
489  //
490  // @param msg The message object to supply the data to be written.
491  // @param buffer The buffer object to write into.
492  // @param dynamic_size An additional offset for messages with dynamically
493  // sized fields. The length of the dynamic field written
494  // will be added to this input value to report how much
495  // larger the message has become.
496  //
497  void operator()( MsgT& msg,
498  BufferT& buffer,
499  size_t& dynamic_offset)
500  {
501  value_type &value = msg.template FieldAt<IdxT>().get();
502 
503  // Exit if there are no entries in this dynamic value.
504  if (value.empty())
505  {
506  return;
507  }
508 
509  // Calculate the total starting offset.
511  + dynamic_offset;
512 
513  size_t bytes_written =
514  SerializeArray(value, buffer, offset);
515 
516  // Update the accumulated dynamic size with the
517  // new length added by the size of this field.
518  dynamic_offset += bytes_written;
519  }
520 };
521 
522 } // namespace detail
523 
524 } // namespace Hg
525 
526 #endif