Alchemy  1.0
A framework to robustly process network messages and structured data
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Hg.h
Go to the documentation of this file.
1 /// @file Hg.h
2 ///
3 /// Contains the Hg (Mercury) Message template definition.
4 /// This format is used to access data fields in formatted message buffers.
5 ///
6 /// The MIT License(MIT)
7 ///
8 /// @copyright 2014 Paul M Watt
9 ///
10 /// Permission is hereby granted, free of charge, to any person obtaining a copy
11 /// of this software and associated documentation files(the "Software"), to deal
12 /// in the Software without restriction, including without limitation the rights
13 /// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
14 /// copies of the Software, and to permit persons to whom the Software is
15 /// furnished to do so, subject to the following conditions :
16 ///
17 /// The above copyright notice and this permission notice shall be included in
18 /// all copies or substantial portions of the Software.
19 ///
20 /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
23 /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 /// THE SOFTWARE.
27 ///
28 // ****************************************************************************
29 #ifndef HG_H_INCLUDED
30 #define HG_H_INCLUDED
31 // Includes *******************************************************************
32 #include <alchemy.h>
33 
34 // Place this guard for all C++ Headers in the Alchemy base directory.
35 #ifdef __cplusplus
36 
37 #include <Hg/msg_buffer.h>
38 #include <Hg/msg_view.h>
39 #include <Hg/pack_message.h>
40 #include <Hg/unpack_message.h>
41 #include <Pb/dynamic.h>
42 
43 
44 namespace Hg
45 {
46 
47 // Forward Declarations *******************************************************
48 template< typename T >
49 size_t dynamic_size_of(const T& msg);
50 
51 // ****************************************************************************
52 template< typename MsgT,
53  typename StorageT
54  >
55 class basic_msg;
56 
57 // ****************************************************************************
58 template< class HgMsgT,
59  bool has_dynamic
60  >
61 struct msg_size;
62 
63 
64 // ****************************************************************************
65 /// An object that defines and manages access to a formatted message buffer.
66 ///
67 /// @paramt HgT A message description that has
68 /// defined the format and utilities for field access.
69 /// @paramt ByteOrderT The specified byte-order for this
70 /// message definition. HostByteOrder is the default.
71 ///
72 template< typename HgT,
73  typename ByteOrderT = Hg::HostByteOrder
74  >
75 class Message
76  : public HgT
77 {
78 public:
79  // Typedefs *****************************************************************
80  typedef Message this_type;
81  typedef HgT base_type;
82 
83  typedef typename
84  base_type::message_type message_type;
85 
86  typedef typename
87  base_type::format_type format_type;
88 
89  typedef typename
90  base_type::storage_type storage_type;
91 
92  typedef typename
93  base_type::const_pointer const_pointer;
94 
95  typedef ByteOrderT byte_order_type;
96 
97 
98  // Construction *************************************************************
99  // **************************************************************************
100  /// Default Constructor
101  ///
103  : base_type()
104  { }
105 
106  // **************************************************************************
107  /// Copy Constructor
108  ///
109  /// @param rhs The Hg message object from which data is copied.
110  ///
111  Message(const message_type& rhs)
112  {
113  *static_cast<message_type*>(this) = rhs;
114  }
115 
116  // **************************************************************************
117  /// Copy Constructor
118  ///
119  /// @param rhs The Hg message object from which data is copied.
120  ///
121  Message(const base_type& rhs)
122  : base_type(rhs)
123  { }
124 
125  // **************************************************************************
126  /// Value constructor. Constructs an initialized message from a raw data buffer.
127  ///
128  /// @param p The initialization data. The contents will only
129  /// be verified for validity of the pointer if the
130  /// size n is larger than zero.
131  /// @param n The size of the buffer in sp.
132  ///
133  Message(const_pointer p, size_t n)
134  : base_type(p,n)
135  { }
136 
137  // Operations ***************************************************************
138  // **************************************************************************
139  /// Assignment Operator
140  ///
141  /// @param rhs Basic message values to initialize this instance.
142  ///
143  Message& operator=(const message_type& rhs)
144  {
145  if (this != &rhs)
146  {
147  *static_cast<message_type*>(this) = rhs;
148  }
149 
150  return *this;
151  }
152 
153  // **************************************************************************
154  /// Indicates if the byte-order of the message is host-order.
155  ///
156  /// @return true - The message is defined in host byte-order.
157  /// false - The mesage is not in host byte-order.
158  /// Most likely net byte-order.
159  ///
160  bool is_host_order() const
161  {
162  return byte_order_type::is_host;
163  }
164 
165  // Give friendship to message instantiations of other types for conversion.
166  template< typename other_MsgT,
167  typename other_ByteOrderT
168  >
169  friend
170  class Message;
171 };
172 
173 
174 
175 // ****************************************************************************
176 /// An object that defines and manages access to a formatted message buffer.
177 ///
178 /// @paramt MsgT A message description that has
179 /// defined the format and utilities for field access.
180 /// The MsgT must define these member-types:
181 /// format_type: TypeList defines the format
182 /// @paramt StorageT StoragePolicy that manages access rules for the buffer.
183 ///
184 /// @note The HG declaration MACROs define a template
185 /// format that is compatible with Hg::basic_msg.
186 ///
187 template< typename MsgT,
188  typename StorageT = Hg::BufferedStoragePolicy
189  >
190 class basic_msg
191  : public MsgT
192 {
193 public:
194  // Typedefs *****************************************************************
195  typedef MsgT message_type;
196 
197  typedef typename
198  MsgT::format_type format_type;
199  typedef StorageT storage_type;
200 
201  typedef MsgBuffer<storage_type> buffer_type;
202 
203  typedef typename
204  message_size_trait<format_type>::type size_trait;
205 
206  typedef typename
207  storage_type::data_type data_type;
208  typedef data_type* pointer;
209  typedef const data_type* const_pointer;
210  typedef MsgT& reference;
211  typedef const MsgT& const_reference;
212 
213  typedef basic_msg< MsgT, StorageT > this_type;
214 
215  typedef Message<this_type,
216  Hg::HostByteOrder> host_t;
217 
218  typedef Message<this_type,
219  Hg::NetByteOrder> net_t;
220 
221  typedef Message<this_type,
222  Hg::BigEndian> big_t;
223 
224  typedef Message<this_type,
225  Hg::LittleEndian> little_t;
226 
227  // Constants ****************************************************************
228  enum { k_size = SizeOf<format_type>::value };
229  ///< Indicates the size in bytes of the
230  /// data buffer managed by this message.
231  static const
233  ///< Indicates if the format of this
234  /// message contains fields that are
235  /// potentially dynamically allocated.
236 
237  // Construction *************************************************************
238  // **************************************************************************
239  /// Default Constructor
240  ///
242  { }
243 
244  // **************************************************************************
245  /// Copy Constructor
246  ///
247  /// @param rhs The Hg message object from which data is copied.
248  ///
249  basic_msg(const basic_msg& rhs)
250  {
251  *static_cast<message_type*>(this) = rhs;
252  }
253 
254  // **************************************************************************
255  /// Value constructor. Constructs an initialized message from a raw data buffer.
256  ///
257  /// @param p The initialization data. The contents will only
258  /// be verified for validity of the pointer if the
259  /// size n is larger than zero.
260  /// @param n The size of the buffer in sp.
261  ///
262  basic_msg(const_pointer p, size_t n)
263  {
264  assign(p,n);
265  }
266 
267  // Operations ***************************************************************
268  // **************************************************************************
269  /// Assignment Operator
270  ///
271  /// @param rhs Basic message values to initialize this instance.
272  ///
273  basic_msg& operator=(const message_type& rhs)
274  {
275  if (this != &rhs)
276  {
277  *static_cast<message_type*>(this) = rhs;
278  }
279 
280  return *this;
281  }
282 
283  // Status *******************************************************************
284  // **************************************************************************
285  /// Indicates if the buffer has allocated space.
286  ///
287  /// @return true - Buffer space has been allocated for the message.
288  /// false - There is no buffer space allocated.
289  ///
290  bool empty() const
291  {
292  return m_msgBuffer.empty();
293  }
294 
295  // **************************************************************************
296  /// Indicates the number of bytes required by this message.
297  ///
298  /// @return The number of bytes that are used to pack this message.
299  ///
300  size_t size() const
301  {
302  return msg_size<this_type,
303  k_has_dynamic>::calculate(*this);
304  }
305 
306  // Methods ******************************************************************
307  // **************************************************************************
308  /// Assigns the contents of an incoming raw memory buffer to the message.
309  ///
310  /// @param pBuffer A memory buffer whose contents will be assigned to
311  /// this message object. The values of the buffer are
312  /// copied into the message.
313  /// @param n The number of bytes held in p_buffer.
314  ///
315  void assign(const_pointer pBuffer, size_t n)
316  {
317  if ( pBuffer
318  && n > 0)
319  {
320  m_msgBuffer.assign(pBuffer, n);
321 
322  // Casting this object to the base object MsgT.
323  // This pointer will accept the data read in from the buffer.
324  basic_msg &refThis = *static_cast<basic_msg*>(this);
325  refThis = unpack_message< message_type,
326  buffer_type,
327  size_trait
328  >(*this, m_msgBuffer);
329  }
330  else
331  {
332 #if ALCHEMY_HAS_EXCEPTIONS
333  throw std::invalid_argument("Hg::basic_msg<>::assign() - pBuffer is invalid or length n is 0");
334 #endif
335  }
336  }
337 
338 #ifdef ALCHEMY_RVALUE_REF_SUPPORTED
339 // TODO: Opportunity, add move assignment to populate the message.
340 // Return and complete this if possible. Try to focus on iterator logic.
341 // // **************************************************************************
342 // /// Assigns the contents of an incoming raw memory buffer to the message.
343 // ///
344 // /// @param pBuffer A memory buffer whose contents will be assigned to
345 // /// this message object. The values of the buffer are
346 // /// copied into the message.
347 // /// @param n The number of bytes held in p_buffer.
348 // ///
349 // void assign(const_pointer pBuffer, size_t n)
350 // {
351 // if ( pBuffer
352 // && n > 0)
353 // {
354 // m_msgBuffer.assign(pBuffer, n);
355 //
356 // // Casting this object to the base object MsgT.
357 // // This pointer will accept the data read in from the buffer.
358 // basic_msg &refThis = *static_cast<Message*>(this);
359 // refThis = unpack_message< message_type,
360 // buffer_type,
361 // size_trait
362 // >(*this, m_msgBuffer);
363 // }
364 // else
365 // {
366 //#if ALCHEMY_HAS_EXCEPTIONS
367 // throw std::invalid_argument("Hg::basic_msg<>::assign() - pBuffer is invalid or length n is 0");
368 //#endif
369 // }
370 // }
371 #endif
372 
373 
374  // **************************************************************************
375  /// Releases any reference to internal memory buffers.
376  /// The message will be MT after this call.
377  ///
378  void clear()
379  {
380  m_msgBuffer.clear();
381  }
382 
383  // **************************************************************************
384  /// Returns a const reference to the underlying collection of value objects.
385  ///
386  const_reference values() const
387  {
388  return *this;
389  }
390 
391  // **************************************************************************
392  /// Returns a reference to the underlying collection of value objects.
393  ///
394  reference values()
395  {
396  return *this;
397  }
398 
399  // **************************************************************************
400  /// Returns a pointer to the memory buffer that contains the packed message.
401  ///
402  const_pointer data() const
403  {
404  basic_msg *pThis = const_cast<basic_msg*>(this);
405  pThis->pack_data();
406 
407  return m_msgBuffer.data();
408  }
409 
410 
411  // **************************************************************************
412  /// Copies the data from this object
413  ///
414  void data(pointer pBuffer, size_t n)
415  {
416  pack_data(pBuffer, n);
417  }
418 
419 
420 private:
421  // Private Data Members *****************************************************
422  buffer_type m_msgBuffer;
423 
424  // **************************************************************************
425  void pack_data()
426  {
427  pack_message< message_type,
428  buffer_type,
429  size_trait
430  >(values(), size(), m_msgBuffer);
431  }
432 
433 
434  // **************************************************************************
435  void pack_data(pointer pBuffer, size_t n)
436  {
437  buffer_type msg_buffer;
438  msg_buffer.assign(pBuffer, n);
439 
440  pack_message< message_type,
441  buffer_type,
442  size_trait
443  >(values(), msg_buffer);
444  }
445 
446  // Give friendship to message instantiations of other types for conversion.
447  template <typename other_MsgT,
448  typename other_StorageT
449  >
450  friend
451  class basic_msg;
452 };
453 
454 
455 // ****************************************************************************
456 /// Reports the number of bytes this message object occupies.
457 /// This instance of size calculates the size for dynamically sized messages.
458 ///
459 /// @return The number of bytes that are used to pack this message.
460 ///
461 template< typename T,
462  bool has_dynamic
463  >
464 struct msg_size
465 {
466  static size_t calculate(const T &msg)
467  {
468  size_t fixed_size = Hg::SizeOf<typename T::format_type>::value;
469  size_t dynamic_size = dynamic_size_of<typename T::message_type,
470  typename T::storage_type>(msg);
471  return fixed_size + dynamic_size;
472  }
473 };
474 
475 // ****************************************************************************
476 /// Specialization returns the size of a fixed size message.
477 ///
478 /// @return The number of bytes that are used to pack this message.
479 ///
480 template< typename T >
481 struct msg_size<T, false>
482 {
483  static size_t calculate(const T &msg)
484  {
486  }
487 };
488 
489 
490 } // namespace Hg
491 
492 // Includes *******************************************************************
493 #include <Hg/message_byte_order.h>
494 #include <Hg/message_dynamic.h>
495 
496 #endif // __cplusplus
497 
498 #endif