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_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 #ifdef __cplusplus
26 
27 // ****************************************************************************
28 // We're potentially using some pretty long type definitions.
29 // For any moderately complex message format, we will almost certainly
30 // trigger this warning with Visual C++.
31 #if defined(_MSC_VER)
32 #pragma warning(disable : 4503) // decorated name length exceeded, name was truncated
33 #endif
34 
35 // Includes *******************************************************************
36 #include <Pb/meta_fwd.h>
37 #include <Pb/auto_index.h>
38 #include <Pb/byte_order.h>
39 #include <Pb/length.h>
40 #include <Pb/offset_of.h>
41 #include <Pb/size_at.h>
42 #include <Pb/size_of.h>
43 #include <Pb/meta_math.h>
44 #include <Pb/dynamic.h>
45 #include <Hg/deduce_msg_type_list.h>
46 #include <Hg/make_Hg_type_list.h>
47 #include <Hg/proxy/deduce_proxy_type.h>
48 
49 
50 // ****************************************************************************
51 // Utility Constructs For Use With Hg Message Types ***************************
52 // ****************************************************************************
53 
54 namespace Hg
55 {
56 
57 // Typedefs *******************************************************************
58 typedef size_t (*pfnGetDatumSize)(const uint8_t*, size_t);
59 
60 
61 // ****************************************************************************
62 /// Indicates the type size the specified message is, static or dynamic.
63 ///
64 /// @paramt T A TypeList definition.
65 ///
66 /// @return A typedef called *type* is defined to return the size trait.
67 /// - static_size_trait indicates a fixed-size message whose
68 /// size is completely known at compile-time.
69 /// - dynamic_size_trait indicates a dyanmically sized message.
70 /// At least some part of the message requires
71 /// runtime processing to determine the size
72 /// of the message.
73 ///
74 template< typename T >
76  : std::conditional
77  < has_dynamic<T>::value,
78  dynamic_size_trait,
79  static_size_trait
80  >
81 { };
82 
83 } // namespace Hg
84 
85 // ****************************************************************************
86 // Abstracted Message Definition MACROS ***************************************
87 // Simplified user MACROS use these definitions.
88 // These definitions have been abstracted to simplify the user header files.
89 // ****************************************************************************
90 
91 // ****************************************************************************
92 #define START_NAMESPACE(NS) namespace NS {
93 #define END_NAMESPACE(NS) }
94 
95 
96 // ****************************************************************************
97 #define DO_REMOVE(...) __VA_ARGS__
98 #define REMOVE_PARENS(N) DO_REMOVE N
99 
100 #define BOOST_PP_REMOVE_PARENS(param) \
101  BOOST_PP_IIF \
102  ( \
103  BOOST_PP_IS_BEGIN_PARENS(param), \
104  DO_REMOVE, \
105  BOOST_PP_IDENTITY \
106  ) \
107  (param)() \
108 
109 // ****************************************************************************
110 #define EACH_TYPE(r, data, i, x) \
111  REMOVE_PARENS(BOOST_PP_TUPLE_ELEM(3,0,x)),
112 
113 #define EACH_PARAM(r, data, i, x) \
114  BOOST_PP_TUPLE_ELEM(3,1,x)(BOOST_PP_TUPLE_ELEM(3,2,x));
115 
116 #define DEFINE_TYPELIST(N,...)\
117  typedef TypeList < __VA_ARGS__ > N;
118 
119 #define DEFINE_PARAMLIST(...)\
120  __VA_ARGS__
121 
122 
123 #if defined(_MSC_VER)
124 #define DEFINE_STRUCT_TYPELIST(N, S) \
125  DEFINE_TYPELIST(N, \
126  BOOST_PP_SEQ_FOR_EACH_I(EACH_TYPE, unused, BOOST_PP_VARIADIC_TO_SEQ(S)) Hg::MT)
127 
128 
129 #define DEFINE_STRUCT_PARAMS(S) \
130  BOOST_PP_SEQ_FOR_EACH_I(EACH_PARAM, unused, BOOST_PP_VARIADIC_TO_SEQ(S))
131 
132 #else
133 
134 #define DEFINE_STRUCT_TYPELIST(N, ...) \
135  DEFINE_TYPELIST(N, \
136  BOOST_PP_SEQ_FOR_EACH_I(EACH_TYPE, unused, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) Hg::MT)
137 
138 
139 #define DEFINE_STRUCT_PARAMS(...) \
140  BOOST_PP_SEQ_FOR_EACH_I(EACH_PARAM, unused, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
141 
142 #endif
143 
144 // TODO: Temporarily will try to put the source back together the way it is currently
145 // structured. Then will move the placement of the definitions to
146 // solve some of the incompatibilities for duplicate types.
147 
148 // ****************************************************************************
149 // Defines the outer value container as well as the formatted type-list.
150 //
151 //#define DEFINE_HG_STRUCT(F, ...)
152 #define DECLARE_STRUCT_HEADER(F, ...) \
153  START_NAMESPACE(Hg) \
154  DEFINE_STRUCT_TYPELIST(F##_tl, __VA_ARGS__) \
155  typedef Hg::make_Hg_type_list<F##_tl>::type F##_Hg; \
156  \
157  struct F \
158  : nested_trait \
159  { \
160  typedef F this_type; \
161  typedef F##_tl format_type; \
162  enum { k_size = SizeOf<format_type>::value }; \
163  enum { k_length = length<format_type>::value }; \
164  \
165  template< size_t IDX> \
166  Datum<IDX, format_type>& FieldAt() \
167  { \
168  typedef Datum < IDX, \
169  format_type> datum_type_t; \
170  return this_type::FieldAtIndex((datum_type_t*)0); \
171  } \
172  template< size_t IDX> \
173  const Datum<IDX, format_type>& const_FieldAt() const \
174  { \
175  return const_cast<this_type*>(this)->FieldAt<IDX>(); \
176  } \
177  BEGIN_COUNTER \
178  \
179  DEFINE_STRUCT_PARAMS(__VA_ARGS__) \
180  DECLARE_STRUCT_FOOTER(F)
181 
182 
183 // ****************************************************************************
184 #define DECLARE_STRUCT_FOOTER(F) \
185  private: \
186  template <typename T, typename U> \
187  size_t DatumSize(T value, U*) \
188  { \
189  return value; \
190  } \
191  \
192  template <typename U> \
193  size_t DatumSize(pfnGetDatumSize ftor, U* buffer) \
194  { \
195  if (buffer->empty()) { return 0; } \
196  return ftor(buffer->data(), buffer->size()); \
197  } \
198  }; \
199  START_NAMESPACE(detail) \
200  template <> \
201  struct field_data_t <F##_Hg> \
202  { \
203  typedef F value_type; \
204  }; \
205  END_NAMESPACE(detail) \
206  END_NAMESPACE(Hg)
207 
208 
209 // ****************************************************************************
210 #define DECLARE_DATUM_ENTRY_IDX(IDX,P) \
211  typedef \
212  Hg::detail::DeduceProxyType < IDX, \
213  format_type>::type Proxy##P; \
214  typedef Proxy##P::datum_type datum_##P; \
215  Proxy##P P; \
216  \
217  datum_##P& FieldAtIndex(const datum_##P*) \
218  { return *static_cast<datum_##P*>(&P); } \
219  \
220  const char* FieldName(const Proxy##P&) { return #P; }
221 
222 // ****************************************************************************
223 #define DECLARE_DATUM_ENTRY_X(P) \
224  INC_COUNTER \
225  DECLARE_DATUM_ENTRY_IDX((COUNTER_VALUE), P)
226 
227 // ****************************************************************************
228 #define D_FUNDAMENTAL(...) DECLARE_DATUM_ENTRY_X __VA_ARGS__
229 
230 
231 #define D_DATUM_X(T,P) (T,D_FUNDAMENTAL,(P))
232 #define D_DATUM(T,P) D_DATUM_X((T),P)
233 
234 // ****************************************************************************
235 #define DECLARE_ARRAY(T,N) std::array<T,N>
236 
237 // ****************************************************************************
238 #define DECLARE_VECTOR(T) std::vector<T>
239 
240 // ****************************************************************************
241 #define DECLARE_ALLOCATED_VECTOR(T,A) std::vector<T,A>
242 
243 // ****************************************************************************
244 #define D_ARRAY(T, N, P) D_DATUM_X((DECLARE_ARRAY(T,N)), P)
245 
246 // ****************************************************************************
247 #define D_DYNAMIC(N,P) \
248  DECLARE_DATUM_ENTRY_X(P) \
249  public: \
250  template <typename U> \
251  size_t Size(U& buffer, datum_##P*) { return DatumSize(N, &buffer); }
252 
253 
254 #define D_DYNAMIC2(...) D_DYNAMIC __VA_ARGS__
255 #define D_VECTOR(T,N,P) ((DECLARE_VECTOR(T)),D_DYNAMIC2,(N,P))
256 
257 
258 #define DECLARE_ARRAY_ENTRY(T, N, P) D_ARRAY(T, N, P)
259 #define DECLARE_DYNAMIC_ENTRY(T, N, P) D_VECTOR(T, N, P)
260 #define DECLARE_ALLOCATOR_ENTRY(T, A, N, P) D_VECTOR(DECLARE_ALLOCATED_VECTOR(T,A), N, P)
261 
262 
263 
264 // ****************************************************************************
265 // Bit Fields *****************************************************************
266 // ****************************************************************************
267 #define DECLARE_PACKED_HEADER(T,C) \
268  START_NAMESPACE(Hg) \
269  struct C; \
270  template <> \
271  struct ContainerSize<C> \
272  : std::integral_constant<size_t, sizeof(T)> { }; \
273  \
274  struct C \
275  : public PackedBits<T> \
276  { \
277  typedef C this_type; \
278  typedef T value_type; \
279  typedef PackedBits<T> base_type; \
280  \
281  C() \
282  : base_type() \
283  { } \
284  \
285  C(const value_type &data_field) \
286  : base_type() \
287  { value(data_field); } \
288  \
289  C(value_type &data_field) \
290  : base_type(data_field) \
291  { } \
292  \
293  C& operator=(const C &rhs) \
294  { value(rhs.value()); \
295  return *this; \
296  } \
297  C& operator=(const value_type &data_field) \
298  { value(data_field); \
299  return *this; \
300  } \
301  \
302  enum { k_offset_0 = 0 }; \
303 
304 
305 // *****************************************************************************
306 #define DECLARE_BIT_FIELD(IDX,P,N) \
307  typedef FieldIndex< IDX, this_type,N> idx_##IDX; \
308  struct P##_tag \
309  { static ptrdiff_t offset() \
310  { return offsetof(this_type, P); } \
311  }; \
312  \
313  typedef BitField < this_type, P##_tag, k_offset_##IDX, N, value_type > P##_t; \
314  enum { TMP_PASTE(k_offset_, TMP_INC(IDX)) = k_offset_##IDX + N }; \
315  \
316  P##_t P; \
317 
318 // *****************************************************************************
319 #define DECLARE_PACKED_FOOTER \
320  }; \
321  END_NAMESPACE(Hg)
322 
323 #else
324 
325 // ****************************************************************************
326 // Declare empty ALCHEMY MACROS for non-C++ builds.
327 //
328 DECLARE_STRUCT_HEADER(NAME, __VA_ARGS__)
329 D_DATUM(TYPE,NAME)
330 DECLARE_ARRAY_ENTRY(TYPE,COUNT,NAME)
331 DECLARE_DYNAMIC_ENTRY(TYPE,COUNT,NAME)
332 D_ALLOCATOR(TYPE,ALLOCATOR,COUNT,NAME)
333 DECLARE_STRUCT_FOOTER(TYPE_LIST)
334 
335 DECLARE_PACKED_HEADER(TYPE,NAME)
336 DECLARE_BIT_FIELD(INDEX, NAME, COUNT)
337 DECLARE_PACKED_FOOTER
338 
339 #endif // __cplusplus
340 
341 #endif