comparison mde/mergetag/dataset.d @ 2:78eb491bd642

mergetag: partially redesigned dataset and text reader classes. Changed text format. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Sat, 03 Nov 2007 15:15:43 +0000
parents 18491334a525
children 9a990644948c
comparison
equal deleted inserted replaced
1:18491334a525 2:78eb491bd642
1 /// This module contains a minimal definition of a MergeTag DataSet. 1 /// This module contains a minimal definition of a MergeTag DataSet.
2 module mde.mergetag.dataset; 2 module mde.mergetag.dataset;
3 3
4 // package imports 4 // package imports
5 import mde.mergetag.parse;
6 import mde.mergetag.exception; 5 import mde.mergetag.exception;
6
7 // other mde imports
8 import mde.text.util;
9 import mde.text.parse;
10 import mde.text.exception : TextParseException;
7 11
8 // tango imports 12 // tango imports
9 import Util = tango.text.Util; 13 import Util = tango.text.Util;
10 import tango.util.log.Log : Log, Logger; 14 import tango.util.log.Log : Log, Logger;
11 15
31 } 35 }
32 36
33 private Logger logger; 37 private Logger logger;
34 static this () { 38 static this () {
35 logger = Log.getLogger ("mde.mergetag.dataset"); 39 logger = Log.getLogger ("mde.mergetag.dataset");
40 }
41
42 struct TextTag {
43 TextTag opCall (char[] _tp, ID _id, char[] _dt) {
44 TextTag ret;
45 ret.tp = _tp;
46 ret.id = _id;
47 ret.dt = _dt;
48 return ret;
49 }
50 char[] tp, dt;
51 ID id;
36 } 52 }
37 53
38 /************************************************************************************************** 54 /**************************************************************************************************
39 * Data class; contains a DataSection class instance for each loaded section of a file. 55 * Data class; contains a DataSection class instance for each loaded section of a file.
40 * 56 *
78 * format except for user-defined types. 94 * format except for user-defined types.
79 * 95 *
80 * Another idea for a DataSection class: 96 * Another idea for a DataSection class:
81 * Use a void*[ID] variable to store all data (may also need a type var for each item). 97 * Use a void*[ID] variable to store all data (may also need a type var for each item).
82 * addTag should call a templated function which calls parse then casts to a void* and stores the data. 98 * addTag should call a templated function which calls parse then casts to a void* and stores the data.
83 * Use a templated get(T)(ID) method which checks the type and casts to T. Small issue with this: storing 99 * Use a templated get(T)(ID) method which checks the type and casts to T.
84 * data in the file with an incorrect type could cause a lot of errors to be thrown in other code.
85 */ 100 */
86 interface DataSection 101 interface DataSection
87 { 102 {
88 /** Handles parsing of data items. 103 /** Handles parsing of data items.
89 * 104 *
90 * Should throw an MTUnknownTypeException for unsupported types, after logging to logger. 105 * Should throw an MTUnknownTypeException for unsupported types, after logging to logger.
91 */ 106 */
92 void addTag (char[],ID,char[]); 107 void addTag (TypeInfo,ID,char[]);
93 //void writeAll (Print!(char)); /// TBD 108 //void writeAll (Print!(char)); /// TBD
94 } 109 }
95 110
96 /** 111 /**
97 * Default DataSection class. 112 * Default DataSection class.
98 * 113 *
99 * Supports all the basic types currently supported and array versions of 114 * Supports all the basic types currently supported and array versions of
100 * each (except no arrays of binary or string types; these are already arrays). 115 * each (except no arrays of binary or string types; these are already arrays).
101 */ 116 */
117 /* Due to a failure to use generic programming techniques for most of this (maybe because it's not
118 * possible or maybe just because I don't know how to use templates properly) a lot of this code is
119 * really horrible and has to refer to EVERY data member.
120 * Be really careful if you add any items to this class.
121 *
122 * I really don't like having to do things like this, but it provides a lot of benefits such as no
123 * need to store types and no need to check an argument's type for every access (this could be done
124 * by throwing errors, but then an incorrect (perhaps hand-edited) data file could cause a lot of
125 * errors to be thrown).
126 */
102 class DefaultData : DataSection 127 class DefaultData : DataSection
103 { 128 {
104 //BEGIN DATA 129 //BEGIN DATA
105 /** Data members for direct access. */ 130 /** Data Members
106 bool [ID] Bool; 131 *
107 byte [ID] Byte; /// ditto 132 * These names are available for direct access.
108 short [ID] Short; /// ditto 133 *
109 int [ID] Int; /// ditto 134 * An alternative access method is to use the provided templates:
110 long [ID] Long; /// ditto 135 * --------------------
111 ubyte [ID] UByte; /// ditto 136 * template Arg(T) {
112 ushort [ID] UShort; /// ditto 137 * alias Name Arg;
113 uint [ID] UInt; /// ditto 138 * }
114 ulong [ID] ULong; /// ditto 139 * --------------------
115 140 *
116 bool[] [ID] BoolA; /// ditto 141 * Use with a mixin or directly:
117 byte[] [ID] ByteA; /// ditto 142 * --------------------
118 short[] [ID] ShortA; /// ditto 143 * mixin Arg!(type);
119 int[] [ID] IntA; /// ditto 144 * auto x = Arg;
120 long[] [ID] LongA; /// ditto 145 *
121 ubyte[] [ID] UByteA; /// ditto 146 * type y = Arg!(type).Arg;
122 ushort[] [ID] UShortA;/// ditto 147 * --------------------
123 uint[] [ID] UIntA; /// ditto 148 * Note: trying to use Arg!(type) to implicitly refer to Arg!(type).Arg causes compiler errors due to
124 ulong[] [ID] ULongA; /// ditto 149 * --- alias Name Arg; ---
125 150 * actually being a mixin.
126 float [ID] Float; /// ditto 151 */
127 double [ID] Double; /// ditto 152
128 real [ID] Real; /// ditto 153 bool [ID] _bool;
129 float[] [ID] FloatA; /// ditto 154 byte [ID] _byte; /// ditto
130 double[] [ID] DoubleA;/// ditto 155 short [ID] _short; /// ditto
131 real[] [ID] RealA; /// ditto 156 int [ID] _int; /// ditto
132 157 long [ID] _long; /// ditto
133 char [ID] Char; /// ditto 158 ubyte [ID] _ubyte; /// ditto
134 char[] [ID] CharA; /// ditto 159 ushort [ID] _ushort; /// ditto
160 uint [ID] _uint; /// ditto
161 ulong [ID] _ulong; /// ditto
162
163 char [ID] _char; /// ditto
164
165 float [ID] _float; /// ditto
166 double [ID] _double; /// ditto
167 real [ID] _real; /// ditto
168
169 bool[] [ID] _boolA; /// ditto
170 byte[] [ID] _byteA; /// ditto
171 short[] [ID] _shortA; /// ditto
172 int[] [ID] _intA; /// ditto
173 long[] [ID] _longA; /// ditto
174 ubyte[] [ID] _ubyteA; /// ditto
175 ushort[] [ID] _ushortA; /// ditto
176 uint[] [ID] _uintA; /// ditto
177 ulong[] [ID] _ulongA; /// ditto
178
179 char[] [ID] _charA; /// ditto
180
181 float[] [ID] _floatA; /// ditto
182 double[] [ID] _doubleA; /// ditto
183 real[] [ID] _realA; /// ditto
135 184
136 /** Alias names */ 185 /** Alias names */
137 alias CharA String; 186 alias _ubyteA _binary;
138 alias UByteA Binary; /// ditto 187 alias _charA _string; /// ditto
139 //END DATA 188 //END DATA
140 189
141 /+ Could use this: 190 void addTag (TypeInfo ti, ID id, char[] dt) { /// for adding tags
142 private template addTagTp(alias Var, T) (ID id, char[] dt) {
143 Var[id] = parse!(T) (dt);
144 }
145 or a mixin.
146 +/
147 // Unfortunately, I think each case needs to be mentioned explicitly to tie it to the correct
148 // data member.
149 void addTag (char[] tp, ID id, char[] dt) { /// for adding tags
150 try { 191 try {
151 postTrim (tp); 192 // crazy way of only writing one parameter on each line:
152 // parse tp, then use if statements to replace the following switch 193 mixin ( `if (ti == typeid(bool)) addTag_add!(bool) (id, dt);`
153 194 ~ addTag_elifIsType_add!(byte)
154 switch(Util.trim(tp)) { 195 ~ addTag_elifIsType_add!(short)
155 case "1": 196 ~ addTag_elifIsType_add!(int)
156 case "bool": 197 ~ addTag_elifIsType_add!(long)
157 Arg!(bool)[id] = parse!(bool) (dt); 198 ~ addTag_elifIsType_add!(ubyte)
158 break; 199 ~ addTag_elifIsType_add!(ushort)
159 case "s8": 200 ~ addTag_elifIsType_add!(uint)
160 case "byte": 201 ~ addTag_elifIsType_add!(ulong)
161 addTagTp!(byte) (id, dt); 202 ~ addTag_elifIsType_add!(char)
162 break; 203 ~ addTag_elifIsType_add!(float)
163 case "s16": 204 ~ addTag_elifIsType_add!(double)
164 case "short": 205 ~ addTag_elifIsType_add!(real)
165 Short[id] = parse!(short) (dt); 206 ~ addTag_elifIsType_add!(bool[])
166 break; 207 ~ addTag_elifIsType_add!(byte[])
167 case "s32": 208 ~ addTag_elifIsType_add!(short[])
168 case "int": 209 ~ addTag_elifIsType_add!(int[])
169 Arg!(int)[id] = parse!(int) (dt); 210 ~ addTag_elifIsType_add!(long[])
170 break; 211 ~ addTag_elifIsType_add!(ubyte[])
171 case "s64": 212 ~ addTag_elifIsType_add!(ushort[])
172 case "long": 213 ~ addTag_elifIsType_add!(uint[])
173 Long[id] = parse!(long) (dt); 214 ~ addTag_elifIsType_add!(ulong[])
174 break; 215 ~ addTag_elifIsType_add!(char[])
175 case "u8": 216 ~ addTag_elifIsType_add!(float[])
176 case "ubyte": 217 ~ addTag_elifIsType_add!(double[])
177 UByte[id] = parse!(ubyte) (dt); 218 ~ addTag_elifIsType_add!(real[])
178 break; 219 );
179 case "u16": 220 } catch (TextParseException) {
180 case "ushort": 221 // Just ignore it. A warning's already been logged.
181 UShort[id] = parse!(ushort) (dt);
182 break;
183 case "u32":
184 case "uint":
185 UInt[id] = parse!(uint) (dt);
186 break;
187 case "u64":
188 case "ulong":
189 ULong[id] = parse!(ulong) (dt);
190 break;
191
192 case "1[]":
193 case "bool[]":
194 BoolA[id] = parse!(bool[]) (dt);
195 break;
196 case "s8[]":
197 case "byte[]":
198 ByteA[id] = parse!(byte[]) (dt);
199 break;
200 case "s16[]":
201 case "short[]":
202 ShortA[id] = parse!(short[]) (dt);
203 break;
204 case "s32[]":
205 case "int[]":
206 IntA[id] = parse!(int[]) (dt);
207 break;
208 case "s64[]":
209 case "long[]":
210 LongA[id] = parse!(long[]) (dt);
211 break;
212 case "u8[]":
213 case "ubyte[]":
214 case "binary":
215 UByteA[id] = parse!(ubyte[]) (dt);
216 break;
217 case "u16[]":
218 case "ushort[]":
219 UShortA[id] = parse!(ushort[]) (dt);
220 break;
221 case "u32[]":
222 case "uint[]":
223 UIntA[id] = parse!(uint[]) (dt);
224 break;
225 case "u64[]":
226 case "ulong[]":
227 ULongA[id] = parse!(ulong[]) (dt);
228 break;
229
230 case "fp32":
231 case "float":
232 Float[id] = parse!(float) (dt);
233 break;
234 case "fp64":
235 case "double":
236 Double[id] = parse!(double) (dt);
237 break;
238 case "fp":
239 case "real":
240 Real[id] = parse!(real) (dt);
241 break;
242 case "fp32[]":
243 case "float[]":
244 FloatA[id] = parse!(float[]) (dt);
245 break;
246 case "fp64[]":
247 case "double[]":
248 DoubleA[id] = parse!(double[]) (dt);
249 break;
250 case "fp[]":
251 case "real[]":
252 RealA[id] = parse!(real[]) (dt);
253 break;
254
255 case "UTF8":
256 case "char":
257 Char[id] = parse!(char) (dt);
258 break;
259 case "UTF8[]":
260 case "char[]":
261 case "string":
262 CharA[id] = parse!(char[]) (dt);
263 break;
264
265 default:
266 logger.warn ("Type not supported: " ~ tp);
267 throw new MTUnknownTypeException ();
268 } 222 }
269 } catch (Exception e) { 223 }
270 // an error should have already been logged 224 private template addTag_elifIsType_add(T) {
271 } 225 const addTag_elifIsType_add = `else if (ti == typeid(`~T.stringof~`)) addTag_add!(`~T.stringof~`) (id, dt);` ;
272 } 226 }
273 227 private void addTag_add(T) (ID id, char[] dt) {
274 private: 228 Arg!(T).Arg[id] = parse!(T) (dt);
275 void addTagTp(T) (ID id, char[] dt) { 229 }
276 Arg!(T)[id] = parse!(T) (dt); 230
277 } 231 void writeTags (out TextTag[] ret) {
278 232 //ret.length = Arg!().length + ...;
279 // use as: mixin Arg!(type); or Arg!(type) 233
280 template Arg(T : bool) { 234
281 alias Bool Arg; 235 }
282 } 236
283 template Arg(T : byte) { 237 /* These make no attempt to check Arg is valid.
284 alias Byte Arg; 238 * But if the symbol doesn't exist the complier will throw an error anyway, e.g.:
285 } 239 * Error: identifier '_boolAA' is not defined
286 template Arg(T : short) { 240 */
287 alias Short Arg; 241 template Arg(T : T[]) {
288 } 242 const ArgString = Arg!(T).ArgString ~ `A`;
289 template Arg(T : int) { 243 mixin(`alias `~ArgString~` Arg;`);
290 alias Int Arg; 244 }
291 } 245 template Arg(T) {
292 template Arg(T : long) { 246 const ArgString = `_` ~ T.stringof;
293 alias Long Arg; 247 mixin(`alias `~ArgString~` Arg;`);
294 }
295 template Arg(T : ubyte) {
296 alias UByte Arg;
297 }
298 template Arg(T : ushort) {
299 alias UShort Arg;
300 }
301 template Arg(T : uint) {
302 alias UInt Arg;
303 }
304 template Arg(T : ulong) {
305 alias ULong Arg;
306 }
307 template Arg(T : bool[]) {
308 alias BoolA Arg;
309 }
310 template Arg(T : byte[]) {
311 alias ByteA Arg;
312 }
313 template Arg(T : short[]) {
314 alias ShortA Arg;
315 }
316 template Arg(T : int[]) {
317 alias IntA Arg;
318 }
319 template Arg(T : long[]) {
320 alias LongA Arg;
321 }
322 template Arg(T : ubyte[]) {
323 alias UByteA Arg;
324 }
325 template Arg(T : ushort[]) {
326 alias UShortA Arg;
327 }
328 template Arg(T : uint[]) {
329 alias UIntA Arg;
330 }
331 template Arg(T : ulong[]) {
332 alias ULongA Arg;
333 }
334 template Arg(T : float) {
335 alias Float Arg;
336 }
337 template Arg(T : double) {
338 alias Double Arg;
339 }
340 template Arg(T : real) {
341 alias Real Arg;
342 }
343 template Arg(T : float[]) {
344 alias FloatA Arg;
345 }
346 template Arg(T : double[]) {
347 alias DoubleA Arg;
348 }
349 template Arg(T : real[]) {
350 alias RealA Arg;
351 }
352 template Arg(T : char) {
353 alias Char Arg;
354 }
355 template Arg(T : char[]) {
356 alias CharA Arg;
357 } 248 }
358 } 249 }
359 250
360 /+ 251 /+
361 class TemplateData : DataSection 252 class TemplateData : DataSection