comparison d2/qtd/Signal.d @ 344:96a75b1e5b26

project structure changes
author Max Samukha <maxter@spambox.com>
date Fri, 14 May 2010 12:14:37 +0300
parents qt/d2/qt/Signal.d@4e31cbd9e20c
children 970332a88b72
comparison
equal deleted inserted replaced
343:552647ec0f82 344:96a75b1e5b26
1 /**
2 *
3 * Copyright: Copyright QtD Team, 2008-2009
4 * Authors: Max Samukha, Eldar Insafutdinov
5 * License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>
6 *
7 * Copyright QtD Team, 2008-2009
8 * Distributed under the Boost Software License, Version 1.0.
9 * (See accompanying file boost-license-1.0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 *
11 */
12 module qtd.Signal;
13
14 public import qt.QGlobal;
15 import qtd.MetaMarshall;
16 import qtd.Meta;
17
18 import core.stdc.stdlib : crealloc = realloc, cfree = free;
19 import core.stdc.string : memmove;
20 import
21 core.thread,
22 core.exception,
23 std.algorithm;
24
25 public import
26 std.typetuple,
27 std.traits,
28 std.conv,
29 std.metastrings;
30
31 public import std.string : strip, toStringz;
32
33 /** The beast that takes string representation of function arguments
34 * and returns an array of default values it doesn't check if arguments
35 * without default values follow the arguments with default values for
36 * simplicity. It is done by mixing in an delegate alias.
37 */
38 string[] defaultValues(string signature)
39 {
40 int braces = 0;
41 bool inDefaultValue = false;
42 bool inStringLiteral = false;
43 string[] res;
44 int startValue = 0;
45
46 if(strip(signature).length == 0)
47 return res;
48
49 foreach (i,c; signature)
50 {
51 if(!inStringLiteral)
52 {
53 if(c == '{' || c =='(')
54 braces++;
55 else if(c == '}' || c ==')')
56 braces--;
57 }
58
59 if(c == '\"' || c == '\'')
60 {
61 if (inStringLiteral)
62 {
63 if(signature[i-1] != '\\')
64 inStringLiteral = false;
65 }
66 else
67 {
68 inStringLiteral = true;
69 }
70 }
71
72 if (!inStringLiteral && braces == 0)
73 {
74 if(c == '=') // found default value
75 {
76 inDefaultValue = true;
77 startValue = i+1;
78 }
79 else if(c == ',') // next function argument
80 {
81 if (inDefaultValue)
82 {
83 res ~= signature[startValue..i];
84 inDefaultValue = false;
85 }
86 }
87 }
88 }
89
90 if (inDefaultValue)
91 res ~= signature[startValue..$];
92
93 return res;
94 }
95
96 int defaultValuesLength(string[] defVals)
97 {
98 return defVals.length;
99 }
100
101
102 // templates for extracting data from static meta-information of signals, slots or properties
103 // public alias TypeTuple!("name", index, OwnerClass, ArgTypes) __signal
104 template MetaEntryName(source...)
105 {
106 enum MetaEntryName = source[0]; // name of the metaentry is the first element
107 }
108
109 template MetaEntryOwner(source...)
110 {
111 alias TupleWrapper!(source[2]).at[0] MetaEntryOwner; // class that owns the property is the third
112 // Compiler #BUG 3092 - evaluates MetaEntryOwner as a Tuple with one element
113 }
114
115 template MetaEntryArgs(source...)
116 {
117 alias ParameterTypeTuple!(source[1]) MetaEntryArgs; // arguments-tuple starts from the fourth position
118 }
119
120 template TupleWrapper(A...) { alias A at; }
121
122 string convertSignalArguments(Args...)()
123 {
124 // void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
125 // at least for string argument need to construct a QString value
126 string res = prepareSignalArguments!(Args);
127
128 res ~= "void*[" ~ __toString(Args.length+1) ~ "] _a = [null";
129 foreach(i, _; Args)
130 res ~= ", " ~ "cast(void*) (" ~ convertSignalArgument!(Args[i])("_t" ~ __toString(i)) ~ ")";
131 res ~= "];\n";
132 return res;
133 }
134
135 public string SignalEmitter(A...)(SignalType signalType, string name, string[] defVals, int localIndex)
136 {
137 string fullArgs, args;
138 int defValsLength = defVals.length;
139 string argsConversion = "";
140 string argsPtr = "null";
141 static if (A.length)
142 {
143 while(A.length != defVals.length)
144 defVals = "" ~ defVals;
145
146 fullArgs = A[0].stringof ~ " _t0";
147 if (defVals[0].length)
148 fullArgs ~= " = " ~ defVals[0];
149 args = "_t0";
150 foreach(i, _; A[1..$])
151 {
152 fullArgs ~= ", " ~ A[i+1].stringof ~ " _t" ~ __toString(i+1);
153 if (defVals[i+1].length)
154 fullArgs ~= " = " ~ defVals[i+1];
155 args ~= ", _t" ~ __toString(i+1);
156 }
157 // build up conversion of signal args from D to C++
158 argsPtr = "_a.ptr";
159 argsConversion = convertSignalArguments!(A)();
160 }
161 string attribute;
162 string sigName = name;
163 if (signalType == SignalType.BindQtSignal)
164 name ~= "_emit";
165 else
166 attribute = "protected ";
167
168 string indexArgs = __toString(localIndex);
169 if(defValsLength > 0)
170 indexArgs ~= ", " ~ __toString(localIndex+defValsLength);
171 string str = attribute ~ "final void " ~ name ~ "(" ~ fullArgs ~ ") {\n" ~ argsConversion ~ "\n"
172 ~ " QMetaObject.activate(this, typeof(this).staticMetaObject, " ~ indexArgs ~ ", " ~ argsPtr ~ ");\n"
173 ~ "}\n"; // ~
174 return str;
175 }
176 /** ---------------- */
177
178
179 const string signalPrefix = "__signal";
180 const string slotPrefix = "__slot";
181
182 enum SignalType
183 {
184 BindQtSignal,
185 NewSignal,
186 NewSlot
187 }
188
189 string signature(T...)(string name)
190 {
191 string res = name ~ "(";
192 foreach(i, _; T)
193 {
194 if(i > 0)
195 res ~= ",";
196 static if (isNativeType!(T[i]))
197 res ~= Unqual!(T[i]).stringof;
198 else
199 res ~= T[i].stringof;
200 }
201 res ~= ")";
202 return res;
203 }
204
205 // ------------------------------------------------------------------
206
207 string[] getSymbols(C)(string prefix)
208 {
209 string[] result;
210 auto allSymbols = __traits(derivedMembers, C);
211 foreach(s; allSymbols)
212 if(ctfeStartsWith(s, prefix))
213 result ~= s;
214 return result;
215 }
216
217 string removePrefix(string source)
218 {
219 foreach (i, c; source)
220 if (c == '_')
221 return source[i+1..$];
222 return source;
223 }
224
225 template Alias(T...)
226 {
227 alias T Alias;
228 }
229
230 // recursive search in the static meta-information
231 template findSymbolsImpl2(C, alias signals, int id)
232 {
233 alias Alias!(__traits(getOverloads, C, signals[id])) current;
234 static if (signals.length - id - 1 > 0)
235 alias TypeTuple!(current, findSymbolsImpl2!(C, signals, id + 1).result) result;
236 else
237 alias current result;
238 }
239
240 template findSymbols2(C, string prefix)
241 {
242 enum signals = getSymbols!(C)(prefix);
243 static if (signals)
244 alias findSymbolsImpl2!(C, signals, 0).result result;
245 else
246 alias TypeTuple!() result;
247 }
248
249 template findSignals(C)
250 {
251 alias findSymbols2!(C, "signal_").result findSignals;
252 }
253
254 template findSlots(C)
255 {
256 alias findSymbols2!(C, "slot_").result findSlots;
257 }
258
259 /* commented out for future when we will implement default arguments
260 template metaMethods(alias func, int index, int defValsCount)
261 {
262 static if(defValsCount >= 0) {
263 alias TupleWrapper!(func, index) current;
264 // pragma(msg, __traits(identifier, (current.at)[0]) ~ " " ~ typeof(&(current.at)[0]).stringof);
265 alias metaMethods!(func, index+1, defValsCount-1).result next;
266 alias TypeTuple!(current, next) result;
267 }
268 else
269 {
270 alias TypeTuple!() result;
271 }
272 }
273 */
274
275 template toMetaEntriesImpl(int id, Methods...)
276 {
277 static if (Methods.length > id)
278 {
279 alias typeof(&Methods[id]) Fn;
280 // commented out for future when we will implement default arguments
281 // enum defValsLength = 0; //ParameterTypeTuple!(Fn).length - requiredArgCount!(Methods[id])();
282 // pragma(msg, __traits(identifier, Methods[id]) ~ " " ~ typeof(&Methods[id]).stringof);
283 // alias metaMethods!(Methods[id], 0, defValsLength).result subres;
284 alias TupleWrapper!(removePrefix(__traits(identifier, Methods[id])), typeof(&Methods[id])) subres;
285 alias TypeTuple!(subres, toMetaEntriesImpl!(id+1, Methods).result) result;
286 }
287 else
288 {
289 alias TypeTuple!() result;
290 }
291 }
292
293 template toMetaEntries(Methods...)
294 {
295 alias TupleWrapper!(toMetaEntriesImpl!(0, Methods).result) toMetaEntries;
296 }