Alchemy  1.0
A framework to robustly process network messages and structured data
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
unpack_message_detail.h
1 /// @file detail/unpack_message.h
2 ///
3 /// Unpacks the bytes from a raw memory buffer into Hg (Mercury).
4 ///
5 /// The MIT License(MIT)
6 /// @copyright 2014 Paul M Watt
7 // ****************************************************************************
8 #ifndef UNPACK_MESSAGE_DETAIL_H_INCLUDED
9 #define UNPACK_MESSAGE_DETAIL_H_INCLUDED
10 // Private Usage Include Guard ************************************************
11 // Only allow this header file to be included through unpack_message.h
12 #ifndef UNPACK_MESSAGE_H_INCLUDED
13 # error Do not include this file directly. Use <detail/unpack_message.h> instead
14 #endif
15 
16 namespace Hg
17 {
18 
19 namespace detail
20 {
21 
22 // ****************************************************************************
23 // A functor to assist in the reading of fundamental types from the message buffer.
24 // This is also the most basic reader, therefore it will act as the default.
25 //
26 // @tparam IdxT [size_t] The index of the field to read.
27 // @tparam MsgT [typename] The message defintition used to parse the
28 // buffer.
29 // @tparam BufferT [typename] The buffer type that provides the data
30 // to read into the message.
31 // @tparam TraitT [typename] Specifies the type trait of T.
32 // This field acts as a descriminator for selecting
33 // the most appropriate construct to read the current
34 // value type from the buffer.
35 //
36 template< size_t IdxT,
37  typename MsgT,
38  typename BufferT,
39  typename TraitT
40  >
41 struct UnpackDatum
42 {
43  // **************************************************************************
44  // Reads a fixed size field from the specified buffer.
45  //
46  // @param msg The message object to supply the data to be read.
47  // @param buffer The buffer object to read from.
48  // @param dynamic_offset An additional offset for messages with dynamically
49  // sized fields.
50  //
51  void operator()(MsgT &msg,
52  BufferT &buffer,
53  size_t dynamic_offset)
54  {
55  typedef typename
57  typename MsgT::format_type
58  >::type proxy_type;
59  typedef typename
60  proxy_type::value_type value_type;
61 
63  + dynamic_offset;
64 
65  buffer.get_data(msg.template FieldAt<IdxT>().get(),
66  offset);
67  }
68 };
69 
70 // ****************************************************************************
71 // ****************************************************************************
72 // Creates a serializer object to read a single datum from the message buffer.
73 //
74 template< size_t IdxT,
75  typename MsgT,
76  typename BufferT
77  >
78 void ReadDatum( MsgT& message,
79  const BufferT& buffer,
80  size_t& dynamic_offset)
81 {
82  typedef typename
84  typename MsgT::format_type
85  >::type proxy_type;
86  typedef typename
87  proxy_type::value_type value_type;
88 
89  UnpackDatum < IdxT,
90  MsgT,
91  const BufferT,
92  typename DeduceTypeTrait<value_type>::type
93  > unpack;
94  unpack(message, buffer, dynamic_offset);
95 }
96 
97 // ****************************************************************************
98 // Reads the data of the specified field from the message buffer.
99 //
100 // @tparam Idx [size_t] The index of this Datum in the container.
101 // @tparam Count [size_t] The number of fields in the container.
102 // @tparam MsgT [typename] The message type, which is a
103 // collection of Datum fields.
104 // @param msg A reference to the msg instance with the data fields.
105 // @param buffer A reference to the buffer that data will be read from.
106 //
107 template <size_t Idx,
108  size_t Count,
109  typename MsgT,
110  typename BufferT
111  >
112 struct UnpackMessageWorker
113 {
114  void operator()( MsgT &msg,
115  const BufferT &buffer )
116  {
117  // Read the current value, then move to the next value for the message.
118  size_t dynamic_offset = 0;
119  ReadDatum< Idx, MsgT, BufferT>(msg, buffer, dynamic_offset);
120 
121  UnpackMessageWorker < Idx+1, Count, MsgT, BufferT> unpack;
122  unpack(msg, buffer);
123  }
124 
125  void operator()( MsgT &msg,
126  const BufferT &buffer,
127  size_t &dynamic_offset)
128  {
129  // Read the current value, then move to the next value for the message.
130  ReadDatum< Idx, MsgT, BufferT>(msg, buffer, dynamic_offset);
131 
132  UnpackMessageWorker < Idx+1, Count, MsgT, BufferT> unpack;
133  unpack(msg, buffer, dynamic_offset);
134  }
135 
136 };
137 
138 // ****************************************************************************
139 // Terminating specialization for the UnpackMessageWorker recursive function.
140 // This function captures the case when the index = count.
141 //
142 template <size_t Idx,
143  typename MsgT,
144  typename BufferT
145  >
146 struct UnpackMessageWorker< Idx,
147  Idx,
148  MsgT,
149  BufferT
150  >
151 {
152  void operator()( MsgT& msg,
153  const BufferT& buffer)
154  { }
155 
156  void operator()( MsgT& msg,
157  const BufferT& buffer,
158  size_t dynamic_offset)
159  { }
160 };
161 
162 
163 // ****************************************************************************
164 // Reads the values of a message structure from a packed memory buffer.
165 //
166 // @param msg_values The message structure that contains the values
167 // to be read.
168 //
169 // @return The buffer that has been allocated to store the
170 // message.
171 //
172 template< typename MsgT,
173  typename BufferT
174  >
175 MsgT& unpack_message( MsgT &msg_values,
176  const BufferT &buffer,
177  const static_size_trait& )
178 {
179  const size_t k_msg_size = Hg::SizeOf<typename MsgT::format_type>::value;
180  // Verify the input buffer contains enough data to populate the message.
181  if ( buffer.empty()
182  || buffer.size() < k_msg_size)
183  {
184 #ifdef ALCHEMY_USES_EXCEPTIONS
185  throw std::length_error("Static unpack_message does not have enough space to complete its operation.");
186 #endif
187 
188  return msg_values;
189  }
190 
191  detail::UnpackMessageWorker < 0,
193  MsgT,
194  BufferT
195  > unpack;
196  unpack(msg_values, buffer);
197  return msg_values;
198 }
199 
200 
201 // ****************************************************************************
202 // Reads the values of a message structure from a packed memory buffer.
203 //
204 // @param msg_values The message structure that contains the values
205 // to be read.
206 // @param buffer The buffer this data should be read from.
207 // @param offset The offset the reading should occur.
208 //
209 // @return The buffer that has been allocated to store the
210 // message.
211 //
212 template< typename MsgT,
213  typename BufferT
214  >
215 size_t unpack_message ( MsgT &msg_values,
216  const BufferT &buffer,
217  size_t offset,
218  const static_size_trait& )
219 {
220  typedef typename
221  std::remove_const<BufferT>::type MutableBuffer;
222 
223  // Calculate the number of bytes that is expected to be read for this message.
225 
226  size_t org_offset = buffer.offset();
227  MutableBuffer working(buffer);
228  working.offset(offset+org_offset);
229  detail::UnpackMessageWorker < 0,
231  MsgT,
232  BufferT
233  > unpack;
234  unpack(msg_values, working);
235 
236  return length;
237 }
238 
239 
240 // ****************************************************************************
241 // Reads the values of a message structure from a packed memory buffer.
242 //
243 // @param msg_values The message structure that contains the values
244 // to be read.
245 // @param buffer The buffer to read from.
246 //
247 // @return The populated message values are returned.
248 //
249 template< typename MsgT,
250  typename BufferT
251  >
252 MsgT& unpack_message( MsgT &msg_values,
253  const BufferT &buffer,
254  const dynamic_size_trait& )
255 {
256  const size_t k_msg_size = Hg::SizeOf<typename MsgT::format_type>::value;
257  // Verify the input buffer contains enough data to populate the minimum size
258  // required by the message.
259  if ( buffer.empty()
260  || buffer.size() < k_msg_size)
261  {
262 #ifdef ALCHEMY_USES_EXCEPTIONS
263  throw std::length_error("Dynamic unpack_message does not have enough space to complete its operation.");
264 #endif
265 
266  return msg_values;
267  }
268 
269  detail::UnpackMessageWorker < 0,
271  MsgT,
272  BufferT
273  > unpack;
274  size_t dynamic_offset = 0;
275  unpack(msg_values, buffer, dynamic_offset);
276  return msg_values;
277 }
278 
279 
280 // ****************************************************************************
281 // Reads the values of a message structure from a packed memory buffer.
282 //
283 // @param msg_values The message structure that contains the values
284 // to be read.
285 // @param buffer The buffer this data should be read from.
286 // @param offset The offset the reading should occur.
287 //
288 // @return The buffer that has been allocated to store the
289 // message.
290 //
291 template< typename MsgT,
292  typename BufferT
293  >
294 size_t unpack_message ( MsgT &msg_values,
295  const BufferT &buffer,
296  size_t offset,
297  const dynamic_size_trait& )
298 {
299  typedef typename
300  std::remove_const<BufferT>::type MutableBuffer;
301 
302  // Calculate the number of bytes that is expected to be read for this message.
304 
305  size_t org_offset = buffer.offset();
306  MutableBuffer working(buffer);
307  working.offset(offset+org_offset);
308  detail::UnpackMessageWorker < 0,
310  MsgT,
311  BufferT
312  > unpack;
313  size_t dynamic_offset = 0;
314  unpack(msg_values, working, dynamic_offset);
315 
316  return length + dynamic_offset;
317 }
318 
319 } // namespace detail
320 
321 } // namespace Hg
322 
323 #endif