annotate d2/qtd/Attribute.d @ 382:1d56b2a2e10c

Fixes to debugging stuff. Added size_t as primitive type to workaround Qwt build failure in debug
author Max Samukha <maxter@spambox.com>
date Mon, 12 Jul 2010 20:36:07 +0300
parents 31520b2c0b3c
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
345
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
1 /*********************************************************
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
2 Copyright: QtD Team, 2010
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
3 Authors: Max Samukha
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
4 License: Boost Software License 1.0
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
5 *********************************************************/
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
6 module qtd.Attribute;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
7
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
8 import
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
9 lds.meta.compiletime,
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
10 std.traits,
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
11 std.conv,
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
12 std.variant,
345
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
13 std.typetuple;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
14
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
15 enum standardNamespace = "qtd";
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
16
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
17 /**
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
18 */
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
19 enum AttributeOptions
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
20 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
21 /**
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
22 */
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
23 none,
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
24
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
25 /**
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
26 Allows multiple attributes of the same category to be associated with the symbol.
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
27 */
346
2691dd58d7e1 fixed QSlitter.getRange
Max Samukha <maxter@spambox.com>
parents: 345
diff changeset
28 allowMultiple = 0x0000_0001,
2691dd58d7e1 fixed QSlitter.getRange
Max Samukha <maxter@spambox.com>
parents: 345
diff changeset
29
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
30 /* internal */ inner = 0x0000_0002,
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
31
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
32 /**
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
33 Specifies that the attribute data are in name-value form.
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
34 */
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
35 nameValue = 0x0000_0004
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
36 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
37
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
38 /**
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
39 When mixed in an aggregate, converts a compile-time tuple to
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
40 members of that aggregate.
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
41 */
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
42 mixin template tupleToMembers!(string nameSpace, size_t index, A...)
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
43 {
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
44 static if (index < A.length)
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
45 {
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
46 enum indexStr = to!string(index);
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
47
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
48 static if (is(__traits(compiles, { struct { typeof(A[index]) x; } }() })))
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
49 mixin("typeof(A[" ~ indexStr ~ "]) " ~ nameSpace ~ ~ " = A[" ~ indexStr ~"];\n" ~ next;
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
50 else
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
51 mixin("alias A[" ~ indexStr ~ "] " ~ nameSpace ~ indexStr ~ ";\n" ~ next;
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
52
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
53 mixin tupleToFields!(nameSpace, index + 1, A);
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
54 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
55 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
56
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
57 /**
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
58 When mixed in an aggregate, converts a compile-time tuple of name-value pairs to
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
59 members of that aggregate.
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
60 */
350
31520b2c0b3c Removed dependency on parent trait and stringof
Max Samukha <maxter@spambox.com>
parents: 348
diff changeset
61 mixin template NameValueTupleToFields(A...)
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
62 {
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
63
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
64 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
65
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
66 version (QtdUnittest)
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
67 {
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
68 unittest
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
69 {
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
70 static int foo()
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
71 {
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
72 return 42;
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
73 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
74
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
75 static struct S
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
76 {
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
77 mixin TupleToFields!("field", 0,
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
78 int,
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
79 "a",
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
80 22,
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
81 foo);
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
82 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
83
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
84 static assert(is(S.field0 == int));
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
85 S s;
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
86 assert(s.field1 == "a");
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
87 assert(s.field2 == "22");
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
88 assert(S.foo() == 42);
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
89 }
345
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
90 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
91
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
92 private template attributeId(alias symbol, uint index = 0)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
93 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
94 enum attributeId = standardNamespace ~ "_attr_" ~ uniqueId!symbol ~ "_" ~ to!string(index);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
95 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
96
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
97 /**
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
98 Attributes allow to associate arbitrary compile-time data
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
99 with a declaration and optionaly make that data available at run-time.
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
100
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
101 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
102 class A
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
103 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
104 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
105 mixin Attribute!(C, "someAttribute", "B");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
106 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
107
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
108 The example above associates the string "B" with class A under the attribute category "someAttribute".
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
109 Multiple data can be associated with an attribute category for a single declaration:
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
110
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
111 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
112 class A
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
113 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
114 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
115 mixin Attribute!(C, "someAttribute", "B");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
116 mixin Attribute!(C, "someAttribute", AttributeOptions.allowMultiple, "C");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
117 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
118
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
119 Attributes of an attribute category can be accessed at compile-time:
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
120
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
121 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
122 alias GetAttributes!(C, "someAttribute") attrs;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
123 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
124
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
125 GetAttribute returns a compile time tuple, which contains "someAttribute" category attributes in the form
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
126 of TypeTupleWrapper instances. The first element of the tuple wrapped in the TypeTupleWrapper
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
127 contains the attribute category name, other elements contain the attrubute data.
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
128
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
129 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
130 alias attrs[0] attr0;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
131 alias attrs[1] attr1;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
132
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
133 static assert(attrs0.tuple[0] == "someAttribute" && attrs0.tuple[1] == "B");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
134 static assert(attrs1.tuple[0] == "someAttribute" && attrs1.tuple[1] == "C");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
135 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
136
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
137 Attributes can be inserted inside the body of a declaration.
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
138 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
139 class A
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
140 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
141 mixin Attribute!("someAttribute", "B");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
142 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
143 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
144
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
145 Attributes can be made available at run time by means of the declaration's meta-object
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
146 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
147 // prints category names of all attributes associated with class A
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
148 auto a = new A;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
149 foreach (attr; a.metaObject.attributes)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
150 writeln(attr.name);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
151 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
152
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
153 Attributes can be specialized
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
154
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
155 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
156 mixin template DbFieldAttribute(alias prop, string columnName)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
157 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
158 mixin Attribute!(prop, "DbFieldAttribute", columnName);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
159 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
160
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
161 class A
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
162 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
163 int value;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
164 mixin DbFieldAttribute!(value, "Value");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
165
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
166 int anotherValue;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
167 mixin DbFieldAttribute!(anotherValue, "Value2");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
168 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
169
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
170 assert(GetAttributes!(A.value, "DbFieldAttribute")[0].tuple[1] == "Value");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
171 assert(GetAttributes!(A.anotherValue, "DbFieldAttribute")[0].tuple[1] == "Value2");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
172 ----
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
173
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
174 */
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
175 mixin template Attribute(alias symbol, string attrClass, A...)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
176 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
177 mixin Attribute!(symbol, attrClass, AttributeOptions.none, A);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
178 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
179
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
180 /// ditto
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
181 mixin template Attribute(alias symbol, string attrClass, AttributeOptions opts, A...)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
182 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
183 mixin AttributeImpl!(symbol, attrClass, opts, 0, A);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
184 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
185
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
186
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
187 /// ditto
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
188 // TODO: probably make this an overload of Attribute
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
189 mixin template InnerAttribute(string attrClass, AttributeOptions opts, A...)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
190 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
191 // BUG: needs to be generalized to accept any parent
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
192 mixin Attribute!(typeof(this), attrClass, opts | AttributeOptions.inner, A);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
193 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
194
350
31520b2c0b3c Removed dependency on parent trait and stringof
Max Samukha <maxter@spambox.com>
parents: 348
diff changeset
195 /// ditto
345
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
196 mixin template InnerAttribute(string attrClass, A...)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
197 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
198 mixin InnerAttribute!(attrClass, AttributeOptions.none, A);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
199 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
200
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
201 private mixin template AttributeImpl(alias symbol, string attrClass, AttributeOptions opts, size_t index, A...)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
202 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
203 private enum attrId = attributeId!(symbol, index) ~ (opts & AttributeOptions.inner ? "_inner" : "");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
204
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
205 static if (is(typeof(mixin(attrId))))
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
206 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
207 mixin ("alias " ~ attrId ~ " attr;");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
208 static if (!(opts & AttributeOptions.allowMultiple))
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
209 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
210 static assert (attr[0] != attrClass, "Multiple " ~ attrClass ~ " attributes are not allowed for "
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
211 ~ __traits(parent, symbol).stringof ~ "." ~ stringOf!symbol);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
212 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
213
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
214 mixin AttributeImpl!(symbol, attrClass, opts, index + 1, A);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
215 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
216 else
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
217 mixin ("alias TypeTuple!(attrClass, A) " ~ attrId ~ ";");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
218 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
219
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
220 /**
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
221 Base class for run time attribute implementations
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
222 */
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
223 abstract class MetaAttribute
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
224 {
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
225 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
226
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
227 /**
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
228 A run-time attribute implementation that stores the attribute data in an
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
229 array of variants.
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
230 */
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
231 final class MetaVariantAttribute : MetaAttribute
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
232 {
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
233 Variant[] values;
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
234
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
235 private this()
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
236 {
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
237 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
238
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
239 static MetaVariantAttribute create(string category, AttributeOptions opts, A...)()
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
240 {
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
241 auto ret = new MetaVariantAttribute;
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
242 super.construct!(category, opts, A)();
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
243 foreach(i, _; A)
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
244 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
245 static if (__traits(compiles, { ret.values ~= Variant(A[i]); }() ))
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
246 ret.values ~= Variant(A[i]);
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
247 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
248 return ret;
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
249 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
250 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
251
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
252 /**
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
253 A run-time attribute implementation that stores the attribute data in an
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
254 assiciative array of variants.
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
255 */
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
256 final class MetaVariantDictAttribute : MetaAttribute
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
257 {
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
258 Variant[string] values;
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
259
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
260 private this()
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
261 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
262 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
263
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
264 static MetaVariantAttribute create(string category, AttributeOptions opts, A...)()
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
265 {
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
266 auto ret = new MetaVariantAttribute;
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
267 super.construct!(category, opts, A)();
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
268 foreach(i, _; A)
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
269 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
270 static if (i % 2 == 0 && __traits(compiles, { ret.values[A[i]] = Variant(A[i + 1]); }() ))
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
271 ret.values[A[i]] ~= Variant(A[i + 1]);
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
272 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
273 return ret;
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
274 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
275 }
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
276
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
277
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
278 /**
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
279 A run-time attribute implementation that stores the attribute data in
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
280 typed fields named fieldN, where N is the index of the original attribute data element.
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
281 */
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
282 abstract class MetaTypedAttribute : MetaAttribute
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
283 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
284 private this() {}
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
285
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
286 static class Impl(A) : typeof(this)
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
287 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
288 private this() {}
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
289
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
290 mixin tupleToMembers!("field", 0, A);
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
291 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
292
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
293 static MetaAttribute create(string category, AttributeOptions opts, A...)()
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
294 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
295 auto ret = new Impl!A;
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
296 super.construct(category, opts, A);
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
297 return ret;
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
298 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
299 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
300
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
301 /**
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
302 A run-time attribute implementation that stores the attribute data in
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
303 typed fields by interpreting the original attribute data as name-value pairs.
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
304 */
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
305 abstract class MetaTypedDictAttribute : MetaAttribute
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
306 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
307 private this() {}
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
308
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
309 static class Impl(A) : typeof(this)
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
310 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
311 private this() {}
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
312
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
313 mixin nameValueTupleToMembers!("", A);
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
314 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
315
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
316 static MetaAttribute create(string category, AttributeOptions opts, A...)()
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
317 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
318 auto ret = new Impl!A;
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
319 super.construct(category, opts, A);
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
320 return ret;
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
321 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
322 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
323
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
324 version (QtdUnittest)
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
325 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
326 unittest
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
327 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
328 static void foo() {}
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
329
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
330 static class C
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
331 {
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
332 mixin InnerAttribute!("someAttribute", MetaVariantAttribute, "22", foo, 33);
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
333 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
334
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
335 auto attr = cast(MetaVariantAttribute) meta!(C).attributes[0];
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
336 assert(attr.name == "someAttribute");
350
31520b2c0b3c Removed dependency on parent trait and stringof
Max Samukha <maxter@spambox.com>
parents: 348
diff changeset
337 assert(attr.length == 2);
348
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
338 assert(attr.values[0] == "22");
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
339 assert(attr.values[1] == 33);
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
340 }
29ea6511681f more attribute prototyping
maxter <spambox@d-coding.com>
parents: 347
diff changeset
341 }
347
970332a88b72 lowered the marshall in rank
maxter <spambox@d-coding.com>
parents: 346
diff changeset
342
345
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
343 private string stringOfFunction(alias symbol)()
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
344 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
345 auto ptrType = typeof(&symbol).stringof;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
346 auto paramList = ParameterTypeTuple!(symbol).stringof;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
347
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
348 string result = ReturnType!(symbol).stringof ~ " " ~ __traits(identifier, symbol) ~ paramList;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
349
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
350 if (ptrType[$ - 1] != ')')
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
351 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
352 for (size_t i = ptrType.length - 2;; --i)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
353 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
354 if (ptrType[i] == ')')
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
355 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
356 result ~= ptrType[i + 1..$];
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
357 break;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
358 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
359 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
360 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
361
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
362 return result;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
363 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
364
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
365 /**
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
366 String of any symbol, including functions
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
367 */
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
368 template stringOf(alias symbol)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
369 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
370 static if (isFunction!symbol)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
371 enum stringOf = stringOfFunction!symbol;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
372 else
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
373 enum stringOf = symbol.stringof;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
374 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
375
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
376 /**
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
377 Returns the string uniquely identifying the
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
378 symbol in its container.
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
379 */
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
380 template uniqueName(alias symbol)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
381 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
382 enum uniqueName = stringOf!symbol;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
383 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
384
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
385 // TODO: works only for simple types. implement
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
386 /**
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
387 *
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
388 */
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
389 string uniqueIdImpl(string symbol)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
390 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
391 char[] r = symbol.dup;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
392 foreach (i, c; symbol)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
393 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
394 if (c == '(' || c == ')' || c == ' ')
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
395 r[i] = '_';
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
396 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
397
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
398 return cast(immutable)r;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
399 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
400
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
401 template uniqueId(alias symbol)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
402 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
403 enum uniqueId = uniqueIdImpl(stringOf!symbol);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
404 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
405
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
406 version (QtdUnittest)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
407 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
408 unittest
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
409 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
410 static class C
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
411 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
412 void foo() const {};
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
413 bool bar(int) { return true; };
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
414 int x;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
415 static assert (stringOf!foo == "void foo() const");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
416 static assert (uniqueName!foo == "void foo() const");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
417 static assert (stringOf!bar == "bool bar(int)");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
418 static assert (uniqueName!bar == "bool bar(int)");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
419 static assert (stringOf!x == "x");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
420 static assert (uniqueName!x == "x");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
421 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
422
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
423 static assert (stringOf!(C.foo) == "void foo() const");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
424 static assert (uniqueName!(C.foo) == "void foo() const");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
425 static assert (stringOf!(C.bar) == "bool bar(int)");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
426 static assert (uniqueName!(C.bar) == "bool bar(int)");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
427
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
428 static assert (stringOf!(C.x) == "x");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
429 static assert (uniqueName!(C.x) == "x");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
430 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
431 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
432
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
433 template truePred(A...)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
434 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
435 enum truePred = true;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
436 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
437
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
438 template attrCategoryPred(string name)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
439 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
440 template attrCategoryPred(A...)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
441 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
442 enum attrCategoryPred = A[0] == name;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
443 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
444 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
445
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
446 /**
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
447 Returns a compile-time tuple of attributes that
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
448 match pred.
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
449 */
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
450 template GetAttributes(alias symbol, alias pred = truePred)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
451 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
452 alias GetAttributesImpl!(symbol, 0, pred).result GetAttributes;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
453 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
454
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
455 /**
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
456 Returns a compile-time tuple of attributes
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
457 matching the specified attribute category.
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
458 */
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
459 template GetAttributes(alias symbol, string attrCategory)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
460 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
461 alias GetAttributes!(symbol, attrCategoryPred!attrCategory) GetAttributes;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
462 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
463
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
464
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
465 template GetAttributesImpl(alias symbol, size_t index, alias pred)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
466 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
467 //pragma(msg, mixin("symbol." ~ attributeId!(symbol, index) ~ "_inner").stringof);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
468 static if (is(typeof(mixin("__traits(parent, symbol)." ~ attributeId!(symbol, index)))))
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
469 mixin ("alias lds.meta.compiletime.Alias!(__traits(parent, symbol))." ~ attributeId!(symbol, index) ~ " attr;");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
470 else static if (is(typeof(mixin("symbol." ~ attributeId!(symbol, index) ~ "_inner"))))
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
471 mixin ("alias symbol." ~ attributeId!(symbol, index) ~ "_inner attr;");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
472
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
473 static if (is(typeof(attr)))
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
474 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
475 alias GetAttributesImpl!(symbol, index + 1, pred).result next;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
476
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
477 static if (pred!attr)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
478 alias TypeTuple!(TypeTupleWrapper!attr, next) result;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
479 else
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
480 alias next result;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
481 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
482 else
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
483 alias TypeTuple!() result;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
484 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
485
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
486 version (QtdUnittest)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
487 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
488 mixin template MyAttribute(alias symbol, A...)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
489 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
490 mixin Attribute!(symbol, "MyAttribute", AttributeOptions.allowMultiple, A);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
491 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
492
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
493 mixin template ClassInfo(string name, alias value)
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
494 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
495 mixin InnerAttribute!("ClassInfo", AttributeOptions.allowMultiple, name, value);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
496 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
497
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
498 unittest
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
499 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
500 static class C
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
501 {
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
502 // inner C attributes
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
503 mixin InnerAttribute!("Inner", 33); // generic
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
504 mixin ClassInfo!("version", 123);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
505 mixin ClassInfo!("author", "James Bond");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
506
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
507
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
508 void foo() {};
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
509 // foo attributes
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
510 mixin Attribute!(foo, "SomeAttribute", 42);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
511 mixin MyAttribute!(foo, 1, 2);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
512 mixin MyAttribute!(foo, 3, 4);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
513
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
514 alias GetAttributes!(typeof(this), "Inner") innerAttrs;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
515 static assert(innerAttrs[0].tuple[0] == "Inner");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
516 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
517 // outer C attribute
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
518 mixin MyAttribute!(C, 24);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
519
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
520 alias GetAttributes!(C, "Inner") innerAttrs;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
521 static assert(innerAttrs[0].tuple[0] == "Inner" && innerAttrs[0].tuple[1] == 33);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
522
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
523 alias GetAttributes!(C, "ClassInfo") ciAttrs;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
524 static assert(ciAttrs[0].tuple[1] == "version" && ciAttrs[0].tuple[2] == 123);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
525
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
526 alias GetAttributes!(C.foo, "SomeAttribute") someAttr;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
527 static assert(someAttr.length == 1);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
528 static assert(someAttr[0].tuple[0] == "SomeAttribute");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
529
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
530 alias GetAttributes!(C.foo, "MyAttribute") myAttrs;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
531
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
532 //COMPILER BUG: cannot 'alias myAttrs[0].tuple myAttrs_0';
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
533 static assert(myAttrs[0].tuple[0] == "MyAttribute");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
534 static assert(myAttrs[0].tuple[1] == 1 && myAttrs[0].tuple[2] == 2);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
535
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
536 static assert(myAttrs[1].tuple[0] == "MyAttribute");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
537 static assert(myAttrs[1].tuple[1] == 3 && myAttrs[1].tuple[2] == 4);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
538
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
539 /+ BUG: Fails: local declarations cannot be accessed as parent.localDecl
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
540 alias GetAttributes!(C, "MyAttribute") myAttrs2;
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
541 static assert(myAttrs2[0].tuple[0] == "MyAttribute");
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
542 static assert(myAttrs2[0].tuple[1] == 24);
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
543 +/
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
544 }
719604a71da0 added attribute exercise
Max Samukha <maxter@spambox.com>
parents:
diff changeset
545 }