Alchemy  1.0
A framework to robustly process network messages and structured data
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
msg_def.h
1 // @file Hg/msg_def.h
2 //
3 // Internal implementation MACROS for message format definitions.
4 //
5 // Contains declaration MACROs implementation to define message buffer formats.
6 // The implementations are hidden behind a second layer to simplify the
7 // header file the user will interact with.
8 //
9 // @note This header file must not be included directly and the
10 // MACROS defined in this file should not be accessed
11 // directly. Include and used the definitions from the file
12 // **<alchemy.h>** instead.
13 //
14 /// The MIT License(MIT)
15 /// @copyright 2014 Paul M Watt
16 // ****************************************************************************
17 #ifndef MSG_DEF_H_INCLUDED
18 #define MSG_DEF_H_INCLUDED
19 // Private Usage Include Guard ************************************************
20 // Only allow this header file to be included through alchemy.h
21 #ifndef ALCHEMY_H_INCLUDED
22 # error Do not include this file directly. Use <alchemy.h> instead
23 #endif
24 
25 // ****************************************************************************
26 // We're potentially using some pretty long type definitions.
27 // For any moderately complex message format, we will almost certainly
28 // trigger this warning with Visual C++.
29 #if defined(_MSC_VER)
30 #pragma warning(disable : 4503) // decorated name length exceeded, name was truncated
31 #endif
32 
33 
34 // ****************************************************************************
35 // Declaration MACROs used for converting from the generic Alchemy definition.
36 // ****************************************************************************
37 
38 // ****************************************************************************
39 // Helps convert generic ALCHEMY datum declarations to elemental declarations.
40 //
41 #define ELEMENTAL_PARAM(r, data, i, x) \
42  , BOOST_PP_CAT(data, x)
43 
44 // TODO: It's possible, GCC may accept this form. If not, refer to the EACH_PARAM MACRO below.
45 
46 // ****************************************************************************
47 // Iterates through each parameter declared in an Alchemy struct declaration.
48 // This for-loop uses the ELEMENTAL_PARAM MACRO above to prepend the
49 // supplied element prefix to the parameter declaration.
50 //
51 #define STRUCT_PARAMS(NAME, EL,S) \
52  (NAME BOOST_PP_SEQ_FOR_EACH_I(ELEMENTAL_PARAM, EL, S))
53 
54 // ****************************************************************************
55 // The generic Alchemy struct definition.
56 // This definition can be converted into any elemental type definition
57 // that is defined for Alchemy.
58 //
59 #define DECLARE_STRUCT(NAME, EL, ...) \
60  EL##DECLARE_STRUCT_HEADER \
61  STRUCT_PARAMS(NAME, EL, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
62 
63 
64 
65 // ****************************************************************************
66 // Helps convert generic ALCHEMY datum declarations to elemental declarations.
67 //
68 #define ELEMENTAL_BITS(r, data, i, x) \
69  , BOOST_PP_CAT(data, x)
70 
71 // ****************************************************************************
72 // Iterates through each parameter declared in an Alchemy struct declaration.
73 // This for-loop uses the ELEMENTAL_PARAM MACRO above to prepend the
74 // supplied element prefix to the parameter declaration.
75 //
76 #define PACKED_PARAMS(TYPE, NAME, EL,S) \
77  (TYPE, NAME BOOST_PP_SEQ_FOR_EACH_I(ELEMENTAL_BITS, EL, S))
78 
79 // ****************************************************************************
80 // The generic Alchemy struct definition.
81 // This definition can be converted into any elemental type definition
82 // that is defined for Alchemy.
83 //
84 #define DECLARE_PACKED(TYPE, NAME, EL, ...) \
85  EL##DECLARE_PACKED_HEADER \
86  PACKED_PARAMS(TYPE, NAME, EL,BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
87 
88 
89 // ****************************************************************************
90 // The version of MACROs defined below are dependent upon the language.
91 //
92 #ifdef __cplusplus
93 
94 // Includes *******************************************************************
95 #include <Pb/meta_fwd.h>
96 #include <Pb/auto_index.h>
97 #include <Pb/byte_order.h>
98 #include <Pb/length.h>
99 #include <Pb/offset_of.h>
100 #include <Pb/size_at.h>
101 #include <Pb/size_of.h>
102 #include <Pb/meta_math.h>
103 #include <Pb/dynamic.h>
104 #include <Hg/deduce_msg_type_list.h>
105 #include <Hg/make_Hg_type_list.h>
106 #include <Hg/proxy/deduce_proxy_type.h>
107 
108 
109 // ****************************************************************************
110 // Utility Constructs For Use With Hg Message Types ***************************
111 // ****************************************************************************
112 
113 namespace Hg
114 {
115 
116 // Typedefs *******************************************************************
117 typedef size_t (*pfnGetDatumSize)(const uint8_t*, size_t);
118 
119 
120 // ****************************************************************************
121 /// Indicates the type size the specified message is, static or dynamic.
122 ///
123 /// @paramt T A TypeList definition.
124 ///
125 /// @return A typedef called *type* is defined to return the size trait.
126 /// - static_size_trait indicates a fixed-size message whose
127 /// size is completely known at compile-time.
128 /// - dynamic_size_trait indicates a dyanmically sized message.
129 /// At least some part of the message requires
130 /// runtime processing to determine the size
131 /// of the message.
132 ///
133 template< typename T >
134 struct message_size_trait
135  : std::conditional
136  < has_dynamic<T>::value,
137  dynamic_size_trait,
138  static_size_trait
139  >
140 { };
141 
142 } // namespace Hg
143 
144 // ****************************************************************************
145 // Abstracted Message Definition MACROS ***************************************
146 // Simplified user MACROS use these definitions.
147 // These definitions have been abstracted to simplify the user header files.
148 // ****************************************************************************
149 
150 // ****************************************************************************
151 #define DO_REMOVE(...) __VA_ARGS__
152 #define REMOVE_PARENS(N) DO_REMOVE N
153 
154 #define BOOST_PP_REMOVE_PARENS(param) \
155  BOOST_PP_IIF \
156  ( \
157  BOOST_PP_IS_BEGIN_PARENS(param), \
158  DO_REMOVE, \
159  BOOST_PP_IDENTITY \
160  ) \
161  (param)() \
162 
163 // ****************************************************************************
164 #define EACH_TYPE(r, data, i, x) \
165  REMOVE_PARENS(BOOST_PP_TUPLE_ELEM(3,0,x)),
166 
167 #define EACH_PARAM(r, data, i, x) \
168  BOOST_PP_TUPLE_ELEM(3,1,x)(BOOST_PP_TUPLE_ELEM(3,2,x));
169 
170 #define DEFINE_TYPELIST(N,...)\
171  typedef TypeList < __VA_ARGS__ > N;
172 
173 
174 #if defined(_MSC_VER)
175 #define DEFINE_STRUCT_TYPELIST(N, S) \
176  DEFINE_TYPELIST(N, \
177  BOOST_PP_SEQ_FOR_EACH_I(EACH_TYPE, unused, BOOST_PP_VARIADIC_TO_SEQ(S)) Hg::MT)
178 
179 
180 #define DEFINE_STRUCT_PARAMS(S) \
181  BOOST_PP_SEQ_FOR_EACH_I(EACH_PARAM, unused, BOOST_PP_VARIADIC_TO_SEQ(S))
182 
183 #else
184 
185 #define DEFINE_STRUCT_TYPELIST(N, ...) \
186  DEFINE_TYPELIST(N, \
187  BOOST_PP_SEQ_FOR_EACH_I(EACH_TYPE, unused, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) Hg::MT)
188 
189 
190 #define DEFINE_STRUCT_PARAMS(...) \
191  BOOST_PP_SEQ_FOR_EACH_I(EACH_PARAM, unused, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
192 
193 #endif
194 
195 // TODO: Temporarily will try to put the source back together the way it is currently
196 // structured. Then will move the placement of the definitions to
197 // solve some of the incompatibilities for duplicate types.
198 
199 // ****************************************************************************
200 // Defines the outer value container as well as the formatted type-list.
201 //
202 #define Hg_DECLARE_STRUCT_HEADER(F, ...) \
203  BEGIN_NAMESPACE(Hg) \
204  DEFINE_STRUCT_TYPELIST(F##_tl, __VA_ARGS__) \
205  typedef Hg::make_Hg_type_list<F##_tl>::type F##_Hg; \
206  \
207  struct F \
208  : nested_trait \
209  { \
210  typedef F this_type; \
211  typedef F##_tl format_type; \
212  enum { k_size = SizeOf<format_type>::value }; \
213  enum { k_length = length<format_type>::value }; \
214  \
215  template< size_t IDX> \
216  Datum<IDX, format_type>& FieldAt() \
217  { \
218  typedef Datum < IDX, \
219  format_type> datum_type_t; \
220  return this_type::FieldAtIndex((datum_type_t*)0); \
221  } \
222  template< size_t IDX> \
223  const Datum<IDX, format_type>& const_FieldAt() const \
224  { \
225  return const_cast<this_type*>(this)->FieldAt<IDX>(); \
226  } \
227  BEGIN_COUNTER \
228  \
229  DEFINE_STRUCT_PARAMS(__VA_ARGS__) \
230  Hg_DECLARE_STRUCT_FOOTER(F)
231 
232 
233 // ****************************************************************************
234 #define Hg_DECLARE_STRUCT_FOOTER(F) \
235  private: \
236  template <typename T, typename U> \
237  size_t DatumSize(T value, U*) \
238  { \
239  return value; \
240  } \
241  \
242  template <typename U> \
243  size_t DatumSize(pfnGetDatumSize ftor, U* buffer) \
244  { \
245  if (buffer->empty()) { return 0; } \
246  return ftor(buffer->data(), buffer->size()); \
247  } \
248  }; \
249  BEGIN_NAMESPACE(detail) \
250  template <> \
251  struct field_data_t <F##_Hg> \
252  { \
253  typedef F value_type; \
254  }; \
255  END_NAMESPACE(detail) \
256  END_NAMESPACE(Hg)
257 
258 
259 // ****************************************************************************
260 #define DECLARE_DATUM_ENTRY_IDX(IDX,P) \
261  typedef \
262  Hg::detail::DeduceProxyType < IDX, \
263  format_type>::type Proxy##P; \
264  typedef Proxy##P::datum_type datum_##P; \
265  Proxy##P P; \
266  \
267  datum_##P& FieldAtIndex(const datum_##P*) \
268  { return *static_cast<datum_##P*>(&P); } \
269  \
270  const char* FieldName(const Proxy##P&) { return #P; }
271 
272 // ****************************************************************************
273 #define DECLARE_DATUM_ENTRY_X(P) \
274  INC_COUNTER \
275  DECLARE_DATUM_ENTRY_IDX((COUNTER_VALUE), P)
276 
277 // ****************************************************************************
278 #define D_FUNDAMENTAL(...) DECLARE_DATUM_ENTRY_X __VA_ARGS__
279 #define D_DATUM_X(T,P) (T,D_FUNDAMENTAL,(P))
280 
281 // ****************************************************************************
282 #define DECLARE_ARRAY(T,N) std::array<T,N>
283 
284 // ****************************************************************************
285 #define DECLARE_VECTOR(T) std::vector<T>
286 
287 // ****************************************************************************
288 #define DECLARE_VECTOR_ALLOCATED(T,A) std::vector<T,A>
289 
290 // ****************************************************************************
291 #define D_ARRAY(T, N, P) D_DATUM_X((DECLARE_ARRAY(T,N)), P)
292 
293 // ****************************************************************************
294 #define D_DYNAMIC(N,P) \
295  DECLARE_DATUM_ENTRY_X(P) \
296  public: \
297  template <typename U> \
298  size_t Size(U& buffer, datum_##P*) { return DatumSize(N, &buffer); }
299 
300 
301 #define D_DYNAMIC2(...) D_DYNAMIC __VA_ARGS__
302 #define D_VECTOR(T,N,P) ((DECLARE_VECTOR(T)),D_DYNAMIC2,(N,P))
303 
304 
305 // ****************************************************************************
306 #define Hg_DECLARE_DATUM(T,P) D_DATUM_X((T),P)
307 #define Hg_DECLARE_ARRAY_DATUM(T, N, P) D_ARRAY(T, N, P)
308 #define Hg_DECLARE_VECTOR_DATUM(T, N, P) D_VECTOR(T, N, P)
309 #define Hg_DECLARE_ALLOCATOR_DATUM(T, A, N, P) D_VECTOR(DECLARE_VECTOR_ALLOCATED(T,A), N, P)
310 
311 
312 
313 // ****************************************************************************
314 // Packed Bit Fields **********************************************************
315 // ****************************************************************************
316 #define Eval_Hg(x) x
317 #define Hg_EACH_BIT_FIELD(r, data, i, x) \
318  BOOST_PP_CAT(data, x)
319 
320 
321 #if defined(_MSC_VER)
322 
323 #define Hg_DEFINE_PACKED_FIELDS(S) \
324  BOOST_PP_SEQ_FOR_EACH_I(Hg_EACH_BIT_FIELD, Eval_, BOOST_PP_VARIADIC_TO_SEQ(S))
325 // BOOST_PP_SEQ_FOR_EACH_I(Hg_EACH_BIT_FIELD, unused, S)
326 
327 #else
328 
329 #define Hg_DEFINE_PACKED_FIELDS(...) \
330  BOOST_PP_SEQ_FOR_EACH_I(C_EACH_BIT_FIELD, unused, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
331 
332 #endif
333 
334 
335 // ****************************************************************************
336 #define Hg_DECLARE_PACKED_HEADER(T,C,...) \
337  BEGIN_NAMESPACE(Hg) \
338  struct C; \
339  template <> \
340  struct ContainerSize<C> \
341  : std::integral_constant<size_t, sizeof(T)> { }; \
342  \
343  struct C \
344  : public PackedBits<T> \
345  { \
346  typedef C this_type; \
347  typedef T value_type; \
348  typedef PackedBits<T> base_type; \
349  \
350  C() \
351  : base_type() \
352  { } \
353  \
354  C(const value_type &data_field) \
355  : base_type() \
356  { value(data_field); } \
357  \
358  C(value_type &data_field) \
359  : base_type(data_field) \
360  { } \
361  \
362  C& operator=(const C &rhs) \
363  { value(rhs.value()); \
364  return *this; \
365  } \
366  C& operator=(const value_type &data_field) \
367  { value(data_field); \
368  return *this; \
369  } \
370  \
371  enum { k_offset_0 = 0 }; \
372  Hg_DEFINE_PACKED_FIELDS(__VA_ARGS__) \
373  }; \
374  END_NAMESPACE(Hg)
375 
376 // *****************************************************************************
377 #define Eval_Hg_DECLARE_BIT_FIELD(IDX,P,N) \
378  typedef FieldIndex< IDX, this_type,N> idx_##IDX; \
379  struct P##_tag \
380  { static ptrdiff_t offset() \
381  { return offsetof(this_type, P); } \
382  }; \
383  \
384  typedef BitField < this_type, P##_tag, k_offset_##IDX, N, value_type > P##_t; \
385  enum { TMP_PASTE(k_offset_, TMP_INC(IDX)) = k_offset_##IDX + N }; \
386  \
387  P##_t P;
388 
389 
390 #else
391 
392 // ****************************************************************************
393 // Declare empty Hg MACROS for non-C++ builds.
394 //
395 #define Hg_DECLARE_STRUCT_HEADER(NAME, ...)
396 #define Hg_DECLARE_DATUM(TYPE,NAME)
397 #define Hg_DECLARE_ARRAY_DATUM(TYPE,COUNT,NAME)
398 #define Hg_DECLARE_VECTOR_DATUM(TYPE,COUNT,NAME)
399 #define Hg_DECLARE_ALLOCATOR_DATUM(TYPE,ALLOCATOR,COUNT,NAME)
400 #define Hg_DECLARE_STRUCT_FOOTER(TYPE_LIST)
401 
402 #define Hg_DECLARE_PACKED_HEADER(TYPE,NAME, ...)
403 #define Hg_DECLARE_BIT_FIELD(INDEX, NAME, COUNT)
404 #define Hg_DECLARE_PACKED_FOOTER
405 
406 #endif // __cplusplus
407 
408 #endif