Mercurial > projects > qtd
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 } |