Grid 0.7.0
MacroMagic.h
Go to the documentation of this file.
1#ifndef GRID_MACRO_MAGIC_H
2#define GRID_MACRO_MAGIC_H
3
5// Strong credit to :
6//
7// http://jhnet.co.uk/articles/cpp_magic
8//
9//
10// "The C Pre-Processor (CPP) is the somewhat basic macro system used by the C
11// programming language to implement features such as #include and #define
12// which allow very simple text-substitutions to be carried out at compile time.
13// In this article we abuse the humble #define to implement if-statements and iteration.
14//
15// Before we begin, a disclaimer: these tricks, while perfectly valid C, should not be
16// considered good development practice and should almost certainly not be used for "real work".
17// That said it can totally be used for fun home-automation projects...
18//
19// https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h
20//
21// The cpp_magic.h license (prior to my modifications):
22/*
23Copyright (c) 2014 Thomas Nixon, Jonathan Heathcote
24
25 Permission is hereby granted, free of charge, to any person obtaining a copy
26 of this software and associated documentation files (the "Software"), to deal
27 in the Software without restriction, including without limitation the rights
28 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 copies of the Software, and to permit persons to whom the Software is
30 furnished to do so, subject to the following conditions:
31
32The above copyright notice and this permission notice shall be included in
33all copies or substantial portions of the Software.
34
35THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41THE SOFTWARE.
42*/
44
45#ifndef MAX
46#define MAX(x,y) ((x)>(y)?(x):(y))
47#define MIN(x,y) ((x)>(y)?(y):(x))
48#endif
49
50#define GRID_MACRO_FIRST(a, ...) a
51#define GRID_MACRO_SECOND(a, b, ...) b
52
53#define GRID_MACRO_EMPTY()
54
55#define GRID_MACRO_EVAL(...) GRID_MACRO_EVAL64(__VA_ARGS__)
56#define GRID_MACRO_EVAL1024(...) GRID_MACRO_EVAL512(GRID_MACRO_EVAL512(__VA_ARGS__))
57#define GRID_MACRO_EVAL512(...) GRID_MACRO_EVAL256(GRID_MACRO_EVAL256(__VA_ARGS__))
58#define GRID_MACRO_EVAL256(...) GRID_MACRO_EVAL128(GRID_MACRO_EVAL128(__VA_ARGS__))
59#define GRID_MACRO_EVAL128(...) GRID_MACRO_EVAL64(GRID_MACRO_EVAL64(__VA_ARGS__))
60#define GRID_MACRO_EVAL64(...) GRID_MACRO_EVAL32(GRID_MACRO_EVAL32(__VA_ARGS__))
61#define GRID_MACRO_EVAL32(...) GRID_MACRO_EVAL16(GRID_MACRO_EVAL16(__VA_ARGS__))
62#define GRID_MACRO_EVAL16(...) GRID_MACRO_EVAL8(GRID_MACRO_EVAL8(__VA_ARGS__))
63#define GRID_MACRO_EVAL8(...) GRID_MACRO_EVAL4(GRID_MACRO_EVAL4(__VA_ARGS__))
64#define GRID_MACRO_EVAL4(...) GRID_MACRO_EVAL2(GRID_MACRO_EVAL2(__VA_ARGS__))
65#define GRID_MACRO_EVAL2(...) GRID_MACRO_EVAL1(GRID_MACRO_EVAL1(__VA_ARGS__))
66#define GRID_MACRO_EVAL1(...) __VA_ARGS__
67
68#define GRID_MACRO_DEFER1(m) m GRID_MACRO_EMPTY()
69#define GRID_MACRO_DEFER2(m) m GRID_MACRO_EMPTY GRID_MACRO_EMPTY()()
70#define GRID_MACRO_DEFER3(m) m GRID_MACRO_EMPTY GRID_MACRO_EMPTY GRID_MACRO_EMPTY()()()
71#define GRID_MACRO_DEFER4(m) m GRID_MACRO_EMPTY GRID_MACRO_EMPTY GRID_MACRO_EMPTY GRID_MACRO_EMPTY()()()()
72
73#define GRID_MACRO_IS_PROBE(...) GRID_MACRO_SECOND(__VA_ARGS__, 0)
74#define GRID_MACRO_PROBE() ~, 1
75
76#define GRID_MACRO_CAT(a,b) a ## b
77
78#define GRID_MACRO_NOT(x) GRID_MACRO_IS_PROBE(GRID_MACRO_CAT(_GRID_MACRO_NOT_, x))
79#define _GRID_MACRO_NOT_0 GRID_MACRO_PROBE()
80
81#define GRID_MACRO_BOOL(x) GRID_MACRO_NOT(GRID_MACRO_NOT(x))
82
83#define GRID_MACRO_IF_ELSE(condition) _GRID_MACRO_IF_ELSE(GRID_MACRO_BOOL(condition))
84#define _GRID_MACRO_IF_ELSE(condition) GRID_MACRO_CAT(_GRID_MACRO_IF_, condition)
85
86#define _GRID_MACRO_IF_1(...) __VA_ARGS__ _GRID_MACRO_IF_1_ELSE
87#define _GRID_MACRO_IF_0(...) _GRID_MACRO_IF_0_ELSE
88
89#define _GRID_MACRO_IF_1_ELSE(...)
90#define _GRID_MACRO_IF_0_ELSE(...) __VA_ARGS__
91
92#define GRID_MACRO_HAS_ARGS(...) GRID_MACRO_BOOL(GRID_MACRO_FIRST(_GRID_MACRO_END_OF_ARGUMENTS_ __VA_ARGS__)())
93#define _GRID_MACRO_END_OF_ARGUMENTS_() 0
94
95#define GRID_MACRO_MAP(m, first, second, ...) \
96 m(first,second) \
97 GRID_MACRO_IF_ELSE(GRID_MACRO_HAS_ARGS(__VA_ARGS__))( \
98 GRID_MACRO_DEFER4(_GRID_MACRO_MAP)()(m, __VA_ARGS__) \
99 )( \
100 /* Do nothing, just terminate */ \
101 )
102
103#define _GRID_MACRO_MAP() GRID_MACRO_MAP
104
106// These are the Grid extensions to serialisation (beyond popping first AND second)
108
109#define GRID_MACRO_MEMBER(A,B) A B;
110
111#define GRID_MACRO_COMP_MEMBER(A,B) result = (result and CompareMember(lhs. B, rhs. B));
112#define GRID_MACRO_OS_WRITE_MEMBER(A,B) os<< #A <<" " #B << " = "; WriteMember( os, obj. B ); os << " ; " <<std::endl;
113#define GRID_MACRO_READ_MEMBER(A,B) ::Grid::read(RD,#B,obj. B);
114#define GRID_MACRO_WRITE_MEMBER(A,B) ::Grid::write(WR,#B,obj. B);
115
116#define GRID_SERIALIZABLE_CLASS_MEMBERS(cname,...)\
117static inline std::string SerialisableClassName(void) {return std::string(#cname);} \
118static constexpr bool isEnum = false; \
119GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_MEMBER,__VA_ARGS__))\
120template <typename T>\
121static inline void write(::Grid::Writer<T> &WR,const std::string &s, const cname &obj){ \
122 push(WR,s);\
123 GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_WRITE_MEMBER,__VA_ARGS__)) \
124 pop(WR);\
125}\
126template <typename T>\
127static inline void read(::Grid::Reader<T> &RD,const std::string &s, cname &obj){ \
128 if (!push(RD,s))\
129 {\
130 std::cout << ::Grid::GridLogWarning << "IO: Cannot open node '" << s << "'" << std::endl; \
131 return;\
132 };\
133 GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_READ_MEMBER,__VA_ARGS__)) \
134 pop(RD);\
135}\
136friend inline std::ostream & operator << (std::ostream &os, const cname &obj ) { \
137 os<<"class "<<#cname<<" {"<<std::endl;\
138 GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_OS_WRITE_MEMBER,__VA_ARGS__)) \
139 os<<"}"; \
140 return os;\
141}\
142friend inline bool operator==(const cname &lhs, const cname &rhs) {\
143 bool result = true;\
144 GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_COMP_MEMBER,__VA_ARGS__))\
145 return result;\
146}
147
148#define GRID_ENUM_TYPE(obj) std::remove_reference<decltype(obj)>::type
149#define GRID_MACRO_ENUMVAL(A,B) A = B,
150#define GRID_MACRO_ENUMCASE(A,B) case GRID_ENUM_TYPE(obj)::A: ::Grid::write(WR,s,#A); break;
151#define GRID_MACRO_ENUMTEST(A,B) else if (buf == #A) {obj = GRID_ENUM_TYPE(obj)::A;}
152#define GRID_MACRO_ENUMCASEIO(A,B) case GRID_ENUM_TYPE(obj)::A: os << #A; break;
153
154#define GRID_SERIALIZABLE_ENUM(name,undefname,...)\
155class name: public ::Grid::Serializable \
156{\
157public:\
158 enum\
159 {\
160 GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_ENUMVAL,__VA_ARGS__))\
161 undefname = -1\
162 };\
163public:\
164 accelerator name(void) : value_(undefname) {}; \
165 accelerator name(int value): value_(value) {}; \
166 static inline std::string SerialisableClassName(void) {return std::string(#name);}\
167 static constexpr bool isEnum = true; \
168 template <typename T>\
169 static inline void write(::Grid::Writer<T> &WR,const std::string &s, const name &obj) \
170 {\
171 switch (obj.value_)\
172 {\
173 GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_ENUMCASE,__VA_ARGS__))\
174 default: ::Grid::write(WR,s,#undefname); break;\
175 }\
176 }\
177 \
178 template <typename T>\
179 static inline void read(::Grid::Reader<T> &RD,const std::string &s, name &obj)\
180 {\
181 std::string buf;\
182 ::Grid::read(RD, s, buf);\
183 if (buf == #undefname) {obj = name::undefname;}\
184 GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_ENUMTEST,__VA_ARGS__))\
185 else {obj = name::undefname;}\
186 }\
187 accelerator_inline operator int(void) const\
188 {\
189 return value_;\
190 }\
191 inline friend std::ostream & operator<<(std::ostream &os, const name &obj)\
192 {\
193 switch (obj) {\
194 GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_ENUMCASEIO,__VA_ARGS__))\
195 default: os << #undefname; break;\
196 }\
197 return os;\
198 }\
199 inline friend std::istream & operator>>(std::istream &is, name &obj)\
200 {\
201 std::string buf;\
202 is >> buf;\
203 if (buf == #undefname) {obj = name::undefname;}\
204 GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_ENUMTEST,__VA_ARGS__))\
205 else {obj = name::undefname;}\
206 return is;\
207 }\
208private:\
209 int value_;\
210};
211
212
213#endif