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_message_detail.h
Go to the documentation of this file.
1 /// @file Hg/detail/pack_message_detail.h
2 ///
3 /// The primary implementation templates for packing Hg Message buffers.
4 /// Specializations for more complex types such as nested messages and vectors
5 /// depend upon the constructs in this header.
6 ///
7 /// The MIT License(MIT)
8 /// @copyright 2014 Paul M Watt
9 // ****************************************************************************
10 #ifndef PACK_MESSAGE_DETAIL_H_INCLUDED
11 #define PACK_MESSAGE_DETAIL_H_INCLUDED
12 // Private Usage Include Guard ************************************************
13 // Only allow this header file to be included through pack_message.h
14 #ifndef PACK_MESSAGE_H_INCLUDED
15 # error Do not include this file directly. Use <detail/pack_message.h> instead
16 #endif
17 
18 namespace Hg
19 {
20 
21 namespace detail
22 {
23 
24 // ****************************************************************************
25 // A functor to assist in the writting of fundamental types to the message buffer.
26 // This implementation is suitable to all fundamental types, BitList Fields,
27 // and fixed-size arrays.
28 //
29 // @tparam T [typename] The fundamental type to be written.
30 // @tparam IsNestedT [bool = false] Indicates this structure writes
31 // fundamental types.
32 //
33 template< size_t IdxT,
34  typename MsgT,
35  typename BufferT,
36  typename TraitT
37  >
38 struct PackDatum
39 {
40  // **************************************************************************
41  // Writes a fixed size field to the specified buffer.
42  //
43  // @param msg The message object to supply the data to be written.
44  // @param buffer The buffer object to write into.
45  // @param dynamic_size An additional offset for messages with dynamically
46  // sized fields.
47  //
48  void operator()(MsgT &msg,
49  BufferT &buffer,
50  size_t dynamic_offset)
51  {
52  typedef typename
54  < IdxT,
55  typename MsgT::format_type
56  >::type proxy_type;
57 
58  typedef typename
59  proxy_type::value_type value_type;
60 
61  value_type &value = msg.template FieldAt<IdxT>().get();
63  + dynamic_offset;
64  buffer.set_data(value, offset);
65  }
66 
67 };
68 
69 
70 // ****************************************************************************
71 // Creates a serializer object to write a single datum to the message buffer.
72 //
73 template< size_t IdxT,
74  typename MsgT,
75  typename BufferT
76  >
77 void WriteDatum(MsgT& message,
78  BufferT& buffer,
79  size_t& dynamic_offset)
80 {
81  typedef typename
83  typename MsgT::format_type
84  >::type proxy_type;
85  typedef typename
86  proxy_type::value_type value_type;
87 
88  PackDatum < IdxT,
89  MsgT,
90  BufferT,
91  typename DeduceTypeTrait<value_type>::type
92  > pack;
93  pack(message, buffer, dynamic_offset);
94 }
95 
96 // ****************************************************************************
97 // Writes the data of the specified field to the message buffer.
98 //
99 // @tparam Idx [size_t] The index of this Datum in the container.
100 // @tparam Count [size_t] The number of fields in the container.
101 // @tparam MsgT [typename] The message type, which is a
102 // collection of Datum fields.
103 // @param msg A reference to the msg instance with the data fields.
104 // @param buffer A reference to the buffer that data will be written.
105 //
106 template <size_t Idx,
107  size_t Count,
108  typename MsgT,
109  typename BufferT
110  >
111 struct PackMessageWorker
112 {
113  void operator()(MsgT &message,
114  BufferT &buffer)
115  {
116  // Write the current value, then move to the next value for the message.
117  size_t dynamic_offset = 0;
118  WriteDatum< Idx, MsgT, BufferT>(message, buffer,dynamic_offset);
119 
120  PackMessageWorker < Idx+1, Count, MsgT, BufferT> pack;
121  pack(message, buffer);
122  }
123 
124  void operator()(MsgT &message,
125  BufferT &buffer,
126  size_t &dynamic_offset)
127  {
128  // Write the current value, then move to the next value for the message.
129  WriteDatum< Idx, MsgT, BufferT>(message, buffer, dynamic_offset);
130 
131  PackMessageWorker < Idx+1, Count, MsgT, BufferT> pack;
132  pack(message, buffer, dynamic_offset);
133  }
134 };
135 
136 // ****************************************************************************
137 // Terminating specialization for the PackMessageWorker recursive function.
138 // This function captures the case when the index = count.
139 //
140 template <size_t Idx,
141  typename MsgT,
142  typename BufferT
143  >
144 struct PackMessageWorker< Idx,
145  Idx,
146  MsgT,
147  BufferT
148  >
149 {
150  void operator()(MsgT& msg,
151  BufferT& buffer)
152  { }
153 
154  void operator()(MsgT& msg,
155  BufferT& buffer,
156  size_t dynamic_offset)
157  { }
158 };
159 
160 // ****************************************************************************
161 // Writes the values of a message structure into a packed memory buffer.
162 //
163 // @param msg_values The message structure that contains the values
164 // to be written.
165 // @param fixed_buffer A Fixed-size MessageBuffer that will accept the
166 // output text from the packed message.
167 //
168 // @return True on success, false otherwise.
169 //
170 template< typename MsgT,
171  typename BufferT
172  >
173 bool
174  pack_fixed_size_message(MsgT& msg_values,
175  BufferT & fixed_buffer,
176  const static_size_trait&)
177 {
178  if (fixed_buffer.size() < Hg::SizeOf<typename MsgT::format_type>::value)
179  {
180  return false;
181  }
182 
183  detail::PackMessageWorker < 0,
185  MsgT,
186  BufferT
187  > pack;
188  pack(msg_values, fixed_buffer);
189 
190  return true;
191 }
192 
193 
194 // ****************************************************************************
195 // Writes the values of a message structure into a packed memory buffer.
196 // This is the top-level function with an offset of 0.
197 //
198 // @param msg_values The message structure that contains the values
199 // to be written.
200 // @param size The calculated size of the buffer required to
201 // hold all of the data for the packed message.
202 //
203 // @return The buffer that has been allocated to store the
204 // message.
205 //
206 template< typename MsgT,
207  typename BufferT
208  >
209 BufferT&
210  pack_message( MsgT& msg_values,
211  size_t size,
212  BufferT & buffer,
213  const static_size_trait&)
214 {
215  // Resize the buffer.
217 
218  detail::PackMessageWorker < 0,
220  MsgT,
221  BufferT
222  > pack;
223  pack(msg_values, buffer);
224  return buffer;
225 }
226 
227 // ****************************************************************************
228 // Writes the values of a message structure into a packed memory buffer.
229 // This function may be called to serialize sub-messages at an offset.
230 //
231 // @param msg_values The message structure that contains the values
232 // to be written.
233 // @param buffer The buffer this data should be written into.
234 // @param offset The offset the writing should be at.
235 //
236 // @return The buffer that has been allocated to store the
237 // message.
238 //
239 template< typename MsgT,
240  typename BufferT
241  >
242 size_t pack_message(MsgT &msg_values,
243  BufferT &buffer,
244  size_t offset,
245  const static_size_trait&)
246 {
247  // Calculate the number of bytes that is expected to be written.
249 
250  size_t org_offset = buffer.offset();
251 
252  // The new adjusted offset must be cumulative in order to
253  // avoid deep nested sub-structures from writing over
254  // previously written material.
255  //
256  // Writing constantly progresses further into the buffer.
257  buffer.offset(offset + org_offset);
258  detail::PackMessageWorker < 0,
260  MsgT,
261  BufferT
262  > pack;
263  pack(msg_values, buffer);
264  // Restore the orignal offset of this buffer.
265  buffer.offset(org_offset);
266 
267  return length;
268 }
269 
270 
271 // ****************************************************************************
272 // Writes the values of a variable-sized message into a packed memory buffer.
273 // A separate instance exists to eliminate dynamic size tests from messages
274 // that are completely fixed in size.
275 // This is the top-level call with a 0 offset.
276 //
277 // @param msg_values The message structure that contains the values
278 // to be written.
279 // @param size The calculated size of the buffer required to
280 // hold all of the data for the packed message.
281 //
282 // @return The buffer that has been allocated to store the
283 // message.
284 //
285 template< typename MsgT,
286  typename BufferT
287  >
288 BufferT &
289  pack_message( MsgT &msg_values,
290  size_t size,
291  BufferT & buffer,
292  const dynamic_size_trait&)
293 {
294  // Resize the buffer.
295  buffer.resize(size);
296 
297  detail::PackMessageWorker < 0,
298  Hg::length<typename MsgT::format_type>::value,
299  MsgT,
300  BufferT
301  > pack;
302  size_t dynamic_offset = 0;
303  pack(msg_values, buffer, dynamic_offset);
304  return buffer;
305 }
306 
307 // ****************************************************************************
308 // Writes the values of a variable-sized message into a packed memory buffer.
309 // A separate instance exists to eliminate dynamic size tests from messages
310 // that are completely fixed in size.
311 // This is a nested call that provides an offset adjustemnt.
312 //
313 // @param msg_values The message structure that contains the values
314 // to be written.
315 // @param buffer The buffer this data should be written into.
316 // @param offset The offset the writing should be at.
317 //
318 // @return The buffer that has been allocated to store the
319 // message.
320 //
321 template< typename MsgT,
322  typename BufferT
323  >
324 size_t pack_message(MsgT &msg_values,
325  BufferT &buffer,
326  size_t offset,
327  const dynamic_size_trait&)
328 {
329  // Calculate the number of bytes that is expected to be written.
331 
332  size_t org_offset = buffer.offset();
333  // The new adjusted offset must be cumulative in order to
334  // avoid deep nested sub-structures from writing over
335  // previously written material.
336  //
337  // Writing constantly progresses further into the buffer.
338  buffer.offset(org_offset + offset);
339  detail::PackMessageWorker < 0,
340  Hg::length<typename MsgT::format_type>::value,
341  MsgT,
342  BufferT
343  > pack;
344  size_t dynamic_offset = 0;
345  pack(msg_values, buffer, dynamic_offset);
346  // Restore the orignal offset of this buffer.
347  buffer.offset(org_offset);
348 
349  return length + dynamic_offset;
350 }
351 
352 } // namespace detail
353 
354 } // namespace Hg
355 
356 #endif