Line data Source code
1 : /* Copyright (C) 2019 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : // Used by Messages.h, so that file stays relatively clean.
19 :
20 : #ifndef MESSAGESSETUP_NOTFIRST
21 : #define MESSAGESSETUP_NOTFIRST
22 :
23 : #include "MessagePasser.h"
24 : #include "SharedTypes.h"
25 : #include "Shareable.h"
26 :
27 : // Structures in this file are passed over the DLL boundary, so some
28 : // carefulness and/or luck is required...
29 :
30 : namespace AtlasMessage
31 : {
32 :
33 : struct IMessage
34 : {
35 : virtual const char* GetName() const = 0;
36 : virtual ~IMessage() {}
37 :
38 : enum Type { Message, Query };
39 : virtual Type GetType() const = 0;
40 : };
41 :
42 :
43 : #define MESSAGESTRUCT(t) \
44 : struct m##t : public IMessage { \
45 : virtual const char* GetName() const { return #t; } \
46 : virtual Type GetType() const { return IMessage::Message; } \
47 : private: \
48 : const m##t& operator=(const m##t&); \
49 : public:
50 :
51 : // Messages for doing/undoing/etc world-altering commands
52 :
53 0 : MESSAGESTRUCT(WorldCommand)
54 : mWorldCommand() {}
55 : virtual void* CloneData() const = 0;
56 : virtual bool IsMergeable() const = 0;
57 : };
58 0 : MESSAGESTRUCT(DoCommand)
59 : mDoCommand(mWorldCommand* c) : name(c->GetName()), data(c->CloneData()) {}
60 : const Shareable<std::string> name;
61 : const Shareable<void*> data;
62 : // 'data' gets deallocated by ~cWhatever in the game thread
63 : };
64 0 : MESSAGESTRUCT(UndoCommand) };
65 0 : MESSAGESTRUCT(RedoCommand) };
66 0 : MESSAGESTRUCT(MergeCommand) };
67 :
68 :
69 0 : struct QueryMessage : public IMessage
70 : {
71 0 : Type GetType() const { return IMessage::Query; }
72 : void Post(); // defined in ScenarioEditor.cpp
73 :
74 : void* m_Semaphore; // for use by MessagePasser implementations (yay encapsulation)
75 : };
76 :
77 :
78 : #define QUERYSTRUCT(t) \
79 : struct q##t : public QueryMessage { \
80 : const char* GetName() const { return #t; } \
81 : private: \
82 : const q##t& operator=(const q##t&); \
83 : public:
84 :
85 :
86 :
87 : const bool MERGE = true;
88 : const bool NOMERGE = false;
89 :
90 :
91 : #define COMMANDDATASTRUCT(t) \
92 : struct d##t { \
93 : private: \
94 : d##t& operator=(const d##t&) = delete; \
95 : public:
96 :
97 : #define COMMANDSTRUCT(t, merge) \
98 : struct m##t : public mWorldCommand, public d##t { \
99 : m##t(const d##t& d) : d##t(d) {} \
100 : const char* GetName() const { return #t; } \
101 : virtual bool IsMergeable() const { return merge; } \
102 : void* CloneData() const { return SHAREABLE_NEW(d##t, (*this)); } \
103 : private: \
104 : const m##t& operator=(const m##t&);\
105 : }
106 :
107 :
108 :
109 : #include <boost/preprocessor/tuple/elem.hpp>
110 : #include <boost/preprocessor/punctuation/comma_if.hpp>
111 : #include <boost/preprocessor/seq/for_each_i.hpp>
112 : #include <boost/preprocessor/comparison/equal.hpp>
113 :
114 : #define B_TYPE(elem) BOOST_PP_TUPLE_ELEM(2, 0, elem)
115 : #define B_NAME(elem) BOOST_PP_TUPLE_ELEM(2, 1, elem)
116 : #define B_CONSTRUCTORARGS(r, data, n, elem) BOOST_PP_COMMA_IF(n) B_TYPE(elem) BOOST_PP_CAT(B_NAME(elem),_)
117 : #define B_CONSTRUCTORTYPES(r, data, n, elem) BOOST_PP_COMMA_IF(n) B_TYPE(elem)
118 : #define B_CONSTRUCTORINIT(r, data, n, elem) BOOST_PP_COMMA_IF(n) B_NAME(elem)(BOOST_PP_CAT(B_NAME(elem),_))
119 : #define B_CONSTMEMBERS(r, data, n, elem) const Shareable< B_TYPE(elem) > B_NAME(elem);
120 : #define B_MEMBERS(r, data, n, elem) Shareable< B_TYPE(elem) > B_NAME(elem);
121 :
122 : /* For each message type, generate something roughly like:
123 : struct mBlah : public IMessage {
124 : const char* GetName() const { return "Blah"; }
125 : mBlah(int in0_, bool in1_) : in0(in0_), in1(in1_) {}
126 : static mBlah* CtorType (int, bool) { return NULL; } // This doesn't do anything useful - it's just to make template-writing easier
127 : const Shareable<int> in0;
128 : const Shareable<bool> in1;
129 : }
130 : */
131 :
132 : #define MESSAGE_WITH_INPUTS(name, vals) \
133 : MESSAGESTRUCT(name) \
134 : m##name( BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORARGS, ~, vals) ) \
135 : : BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORINIT, ~, vals) {} \
136 : static m##name* CtorType( BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORTYPES, ~, vals) ) { return NULL; } \
137 : BOOST_PP_SEQ_FOR_EACH_I(B_CONSTMEMBERS, ~, vals) \
138 : }
139 :
140 : #define MESSAGE_WITHOUT_INPUTS(name, vals) \
141 : MESSAGESTRUCT(name) \
142 : m##name() {} \
143 : static m##name* CtorType() { return NULL; } \
144 : }
145 :
146 : #define MESSAGE(name, vals) \
147 : BOOST_PP_IIF( \
148 : BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE((~)vals), 1), \
149 : MESSAGE_WITHOUT_INPUTS, \
150 : MESSAGE_WITH_INPUTS) \
151 : (name, vals)
152 :
153 :
154 :
155 : #define COMMAND(name, merge, vals) \
156 : COMMANDDATASTRUCT(name) \
157 : d##name( BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORARGS, ~, vals) ) \
158 : : BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORINIT, ~, vals) {} \
159 : BOOST_PP_SEQ_FOR_EACH_I(B_CONSTMEMBERS, ~, vals) \
160 : }; \
161 : COMMANDSTRUCT(name, merge)
162 :
163 :
164 : // Need different syntax depending on whether there are some input values in the query:
165 :
166 : #define QUERY_WITHOUT_INPUTS(name, in_vals, out_vals) \
167 : QUERYSTRUCT(name) \
168 : q##name() {} \
169 : static q##name* CtorType() { return NULL; } \
170 : BOOST_PP_SEQ_FOR_EACH_I(B_MEMBERS, ~, out_vals) /* other members */ \
171 : }
172 :
173 : #define QUERY_WITH_INPUTS(name, in_vals, out_vals) \
174 : QUERYSTRUCT(name) \
175 : q##name( BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORARGS, ~, in_vals) ) \
176 : : BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORINIT, ~, in_vals) {} \
177 : static q##name* CtorType( BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORTYPES, ~, in_vals) ) { return NULL; } \
178 : BOOST_PP_SEQ_FOR_EACH_I(B_CONSTMEMBERS, ~, in_vals) \
179 : BOOST_PP_SEQ_FOR_EACH_I(B_MEMBERS, ~, out_vals) \
180 : }
181 :
182 : #define QUERY(name, in_vals, out_vals) \
183 : BOOST_PP_IIF( \
184 : BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE((~)in_vals), 1), \
185 : QUERY_WITHOUT_INPUTS, \
186 : QUERY_WITH_INPUTS) \
187 : (name, in_vals, out_vals)
188 :
189 : //////////////////////////////////////////////////////////////////////////
190 : //////////////////////////////////////////////////////////////////////////
191 :
192 : #else // MESSAGESSETUP_NOTFIRST => clean up the mess
193 :
194 : #undef MESSAGESTRUCT
195 : #undef QUERYSTRUCT
196 : #undef COMMANDDATASTRUCT
197 : #undef COMMANDSTRUCT
198 : #undef B_TYPE
199 : #undef B_NAME
200 : #undef B_CONSTRUCTORARGS
201 : #undef B_CONSTRUCTORTYPES
202 : #undef B_CONSTRUCTORINIT
203 : #undef B_CONSTMEMBERS
204 : #undef B_MEMBERS
205 : #undef MESSAGE
206 : #undef COMMAND
207 : #undef QUERY_WITHOUT_INPUTS
208 : #undef QUERY_WITH_INPUTS
209 : #undef QUERY
210 :
211 : }
212 :
213 : #endif
|