Alchemy  1.0
A framework to robustly process network messages and structured data
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
message_byte_order_detail.h
Go to the documentation of this file.
1 /// @file Hg/detail/message_byte_order_detail.h
2 ///
3 /// Internal details for the implementation of byte-order conversion of messages.
4 ///
5 /// The MIT License(MIT)
6 /// @copyright 2014 Paul M Watt
7 // ****************************************************************************
8 #ifndef MESSAGE_BYTE_ORDER_DETAIL_H_INCLUDED
9 #define MESSAGE_BYTE_ORDER_DETAIL_H_INCLUDED
10 
11 #include <Pb/byte_order.h>
12 
13 namespace Hg
14 {
15 
16 namespace detail
17 {
18 
19 // Forward Declarations ******************************************************
20 // ****************************************************************************
21 template< typename FromMsgT,
22  typename ToMsgT
23  >
24 struct ByteOrderConversionFunctor;
25 
26 
27 // ****************************************************************************
28 template< typename MsgT,
29  typename ByteOrderT
30  >
31 class Message;
32 
33 // ****************************************************************************
34 template< typename MsgT,
35  typename StorageT
36  >
37 class basic_msg;
38 
39 
40 // ****************************************************************************
41 // Parameterized function to facilitate the conversion of a Hg::Message to
42 // from byte-order A to byte-order B. Note that A and B can be the same type.
43 //
44 // @param T [typename] The Hg::Message format definition of the
45 // message to be converted.
46 // @param from The message object to convert from.
47 //
48 // @return A Hg::Message object using the same format and data type as the
49 // input buffer will be returned. The data in the buffer will
50 // be in host byte-order.
51 //
52 // If the input format was already in host byte-order,
53 // no conversion operations will be performed.
54 //
55 template< typename T,
56  typename OrderT
57  >
59  convert_byte_order( T& from,
61 {
62  typedef typename
63  T::format_type format_type;
64 
65  // Initialize a functor to convert the data byte order,
66  // then call this operation for each element in the defined message.
67  detail::ByteOrderConversionFunctor
68  < T,
70  > ftor(from, to);
71 
72  Hg::ForEachType < 0,
74  format_type
75  > (ftor);
76 
77  return ftor.output;
78 }
79 
80 // ****************************************************************************
81 // A functor to assist in the conversion of fundamental types from one byte-order
82 // to another.
83 //
84 // @tparam T [typename] The fundamental type to be converted.
85 // @tparam TraitT [typename] Specifies the type trait of T.
86 // This field acts as a descriminator for selecting
87 // the most appropriate construct to convert byte-order.
88 //
89 template< typename T,
90  typename StorageT,
91  typename TraitT
92  >
93 struct ConvertEndianess
94 {
95  void operator()(const T &input,
96  T &output)
97  {
98  output = EndianSwap(input);
99  }
100 };
101 
102 // ****************************************************************************
103 // A specialized functor to convert nested types.
104 //
105 // @tparam T [typename] The value_type for this specialization
106 // is actually a format_type for the nested structure.
107 //
108 template< typename T,
109  typename StorageT
110  >
111 struct ConvertEndianess<T, StorageT, nested_trait>
112 {
113  template <typename NestedValueT>
114  void operator()(const NestedValueT &input,
115  NestedValueT &output)
116  {
117  // Byte-order swapping is a symetric action.
118  // The important goal is to define two differing orders to ensure
119  // that the byte-orders are swapped.
120  typedef Hg::LittleEndian from_order;
121  typedef Hg::BigEndian to_order;
122  typedef typename
124  typedef typename
126 
127  // Construct a shallow message wrapper around the nested data.
128  from_type from(input);
129  to_type to;
130 
131  // Pass this message to be byte-order swapped.
132  output = convert_byte_order<from_type,
133  to_order>(from, to).values();
134  }
135 };
136 
137 // ****************************************************************************
138 // A specialized functor to convert array types.
139 //
140 // @tparam T [typename] The value_type for this specialization.
141 //
142 template< typename T,
143  typename StorageT
144  >
145 struct ConvertEndianess<T, StorageT, array_trait>
146 {
147  template <typename ArrayValueT>
148  void operator()(const ArrayValueT &input,
149  ArrayValueT &output)
150  {
151  // Get the trait for the value_type managed by the array.
152  typedef typename
153  ArrayValueT::value_type value_type;
154 
155  typedef typename
156  DeduceTypeTrait<value_type>::type type_trait;
157 
158  // Convert with the byte-order conversion functors to detect and handle
159  // any nested array items, or arrays of arrays etc...
160  ConvertEndianess< value_type,
161  StorageT,
162  type_trait
163  > swap_order;
164  // Perform a conversion on every item in the array.
165  for (size_t index = 0; index < input.size(); ++index)
166  {
167  swap_order(input[index], output[index]);
168  }
169  }
170 };
171 
172 // ****************************************************************************
173 // A specialized functor to convert vector types.
174 //
175 // @tparam T [typename] The value_type for this specialization.
176 //
177 template< typename T,
178  typename StorageT
179  >
180 struct ConvertEndianess<T, StorageT, vector_trait>
181 {
182  template <typename VectorValueT>
183  void operator()(const VectorValueT &input,
184  VectorValueT &output)
185  {
186  // Get the trait for the value_type managed by the array.
187  typedef typename
188  VectorValueT::value_type value_type;
189 
190  typedef typename
191  DeduceTypeTrait<value_type>::type type_trait;
192 
193  // Convert with the byte-order conversion functors to detect and handle
194  // any nested array items, or arrays of arrays etc...
195  ConvertEndianess< value_type,
196  StorageT,
197  type_trait
198  > swap_order;
199  // Allocate space for the output vector.
200  output.resize(input.size());
201 
202  // Perform a conversion on every item in the vector.
203  for (size_t index = 0; index < input.size(); ++index)
204  {
205  swap_order(input[index], output[index]);
206  }
207  }
208 };
209 
210 // ****************************************************************************
211 // ****************************************************************************
212 // A functor to assist in the conversion of a messages data-fields from
213 // network byte-order to host byte-order.
214 //
215 // @param FromMsgT [typename] The input message type.
216 // @param ToMsgT [typename] The output message type.
217 //
218 template< typename FromMsgT,
219  typename ToMsgT
220  >
221 struct ByteOrderConversionFunctor
222 {
223  // Typedefs *****************************************************************
224  typedef FromMsgT from_message_type;
225  typedef ToMsgT to_message_type;
226  typedef typename
227  from_message_type::message_type message_type;
228  typedef typename
229  message_type::format_type format_type;
230  typedef typename
231  from_message_type::storage_type storage_type;
232 
233  // Data Members *************************************************************
234  from_message_type& input;
235  to_message_type& output;
236 
237  // **************************************************************************
238  // Value constructor that initializes the input message to be converted.
239  //
240  // @param rhs The basic_msg object that contains the input data.
241  //
242  explicit
243  ByteOrderConversionFunctor(from_message_type& from,
244  to_message_type& to)
245  : input(from)
246  , output(to)
247  { }
248 
249  // **************************************************************************
250  // Parameterized function operator
251  //
252  // This function provides the ability for every type of data field to be
253  // converted by this functor.
254  //
255  // @paramT size_t Parameterized value that specifies the index
256  // of the data field to be converted.
257  // @paramT value_type [typename] The type of the data element T.
258  // @param unnamed An unused variable to disambiguate the appropriate
259  // specialization function for the compiler to select.
260  //
261  template <size_t Idx,
262  typename value_t>
263  void operator()(const value_t*)
264  {
265  typedef typename
267  format_type
268  >::type proxy_type;
269  typedef typename
270  proxy_type::value_type value_type;
271 
272  // The context for which the const input parameter is
273  // being used here does not change the value.
274  // However, a non-const version of get() causes conflicts.
275  // Therefore, casting away const is the safest and cleanest solution.
276  from_message_type &mutable_input = const_cast<from_message_type &>(input);
277 
278  value_type& from_value = mutable_input.template FieldAt<Idx>().get();
279 
280  // Create an instance of a selection template that will choose between
281  // nested processing, and value conversion.
282  ConvertEndianess< value_type,
283  storage_type,
284  typename DeduceTypeTrait<value_type>::type
285  > swap_order;
286  // Swap directly into the value storage for the conversion output.
287  swap_order( from_value,
288  output.template FieldAt<Idx>().get());
289  }
290 };
291 
292 
293 // ****************************************************************************
294 // ****************************************************************************
295 // A no-op functor specialization to handle Message to Message conversions
296 // of the same byte-order.
297 //
298 // @param MsgT [typename] The input/output message type.
299 // These types are the same, and therefore will not
300 // trigger any byte-order swap operations.
301 //
302 template< typename T >
303 struct ByteOrderConversionFunctor <T, T>
304 {
305  // Typedefs *****************************************************************
306  typedef T from_message_type;
307  typedef T to_message_type;
308 
309  // Data Members *************************************************************
310  const from_message_type &input;
311  to_message_type& output;
312 
313  // **************************************************************************
314  /// Value constructor that initializes the input message to be converted.
315  ///
316  /// @param rhs The basic_msg object that contains the input data.
317  ///
318  explicit
319  ByteOrderConversionFunctor(const from_message_type& from,
320  to_message_type& to)
321  : input(from)
322  , output(to)
323  { }
324 
325  // **************************************************************************
326  /// Parameterized function operator
327  ///
328  /// This function provides the ability for every type of data field to be
329  /// converted by this functor.
330  ///
331  /// @param size_t Parameterized value that specifies the index
332  /// of the data field to be converted.
333  /// @param value_type [typename] The type of the data element T.
334  /// @param unnamed An unused variable to disambiguate the appropriate
335  /// specialization function for the compiler to select.
336  ///
337  template <size_t Idx,
338  typename value_t>
339  void operator()(const value_t*)
340  {
341  // The context for which the const input parameter is
342  // being used here does not change the value.
343  // However, a non-const version of get() causes conflicts.
344  // Therefore, casting away const is the safest and cleanest solution.
345  from_message_type &mutable_input = const_cast<from_message_type &>(input);
346  // Simply copy the input value to the output value.
347  output.template FieldAt<Idx>().set(
348  mutable_input.template FieldAt<Idx>().get()
349  );
350  }
351 };
352 
353 } // namespace detail
354 
355 } // namespace Hg
356 
357 #endif