Mercurial > projects > dmdscript-tango
comparison dmdscript_tango/property.d @ 0:55c2951c07be
initial, files origin, premoved tree
author | saaadel |
---|---|
date | Sun, 24 Jan 2010 12:34:47 +0200 |
parents | |
children | 8363a4bf6a8f |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:55c2951c07be |
---|---|
1 | |
2 /* Digital Mars DMDScript source code. | |
3 * Copyright (c) 2000-2002 by Chromium Communications | |
4 * D version Copyright (c) 2004-2006 by Digital Mars | |
5 * All Rights Reserved | |
6 * written by Walter Bright | |
7 * www.digitalmars.com | |
8 * Use at your own risk. There is no warranty, express or implied. | |
9 * License for redistribution is by the GNU General Public License in gpl.txt. | |
10 * | |
11 * A binary, non-exclusive license for commercial use can be | |
12 * purchased from www.digitalmars.com/dscript/buy.html. | |
13 * | |
14 * DMDScript is implemented in the D Programming Language, | |
15 * www.digitalmars.com/d/ | |
16 * | |
17 * For a C++ implementation of DMDScript, including COM support, | |
18 * see www.digitalmars.com/dscript/cppscript.html. | |
19 */ | |
20 | |
21 | |
22 module dmdscript.property; | |
23 | |
24 import dmdscript.script; | |
25 import dmdscript.value; | |
26 import dmdscript.identifier; | |
27 | |
28 import std.c.string; | |
29 | |
30 // attribute flags | |
31 enum | |
32 { | |
33 ReadOnly = 0x001, | |
34 DontEnum = 0x002, | |
35 DontDelete = 0x004, | |
36 Internal = 0x008, | |
37 Deleted = 0x010, | |
38 Locked = 0x020, | |
39 DontOverride = 0x040, | |
40 KeyWord = 0x080, | |
41 DebugFree = 0x100, // for debugging help | |
42 Instantiate = 0x200, // For COM named item namespace support | |
43 } | |
44 | |
45 struct Property | |
46 { | |
47 uint attributes; | |
48 | |
49 Value value; | |
50 } | |
51 | |
52 extern (C) | |
53 { | |
54 /* These functions are part of the internal implementation of Phobos | |
55 * associative arrays. It's faster to use them when we have precomputed | |
56 * values to use. | |
57 */ | |
58 | |
59 struct Array | |
60 { | |
61 int length; | |
62 void* ptr; | |
63 } | |
64 | |
65 struct aaA | |
66 { | |
67 aaA *left; | |
68 aaA *right; | |
69 hash_t hash; | |
70 /* key */ | |
71 /* value */ | |
72 } | |
73 | |
74 struct BB | |
75 { | |
76 aaA*[] b; | |
77 size_t nodes; // total number of aaA nodes | |
78 } | |
79 | |
80 struct AA | |
81 { | |
82 BB* a; | |
83 version (X86_64) | |
84 { | |
85 } | |
86 else | |
87 { | |
88 // This is here only to retain binary compatibility with the | |
89 // old way we did AA's. Should eventually be removed. | |
90 int reserved; | |
91 } | |
92 } | |
93 | |
94 long _aaRehash(AA* paa, TypeInfo keyti); | |
95 | |
96 /************************ | |
97 * Alternate Get() version | |
98 */ | |
99 | |
100 Property* _aaGetY(hash_t hash, Property[Value]* bb, Value* key) | |
101 { | |
102 aaA* e; | |
103 auto aa = cast(AA*)bb; | |
104 | |
105 if (!aa.a) | |
106 aa.a = new BB(); | |
107 | |
108 auto aalen = aa.a.b.length; | |
109 if (!aalen) | |
110 { | |
111 alias aaA *pa; | |
112 | |
113 aalen = 97; | |
114 aa.a.b = new pa[aalen]; | |
115 } | |
116 | |
117 //printf("hash = %d\n", hash); | |
118 size_t i = hash % aalen; | |
119 auto pe = &aa.a.b[i]; | |
120 while ((e = *pe) != null) | |
121 { | |
122 if (hash == e.hash) | |
123 { | |
124 Value* v = cast(Value*)(e + 1); | |
125 if (key.vtype == V_NUMBER) | |
126 { if (v.vtype == V_NUMBER && key.number == v.number) | |
127 goto Lret; | |
128 } | |
129 else if (key.vtype == V_STRING) | |
130 { if (v.vtype == V_STRING && key.string is v.string) | |
131 goto Lret; | |
132 } | |
133 auto c = key.opCmp(v); | |
134 if (c == 0) | |
135 goto Lret; | |
136 pe = (c < 0) ? &e.left : &e.right; | |
137 } | |
138 else | |
139 pe = (hash < e.hash) ? &e.left : &e.right; | |
140 } | |
141 | |
142 // Not found, create new elem | |
143 //printf("\tcreate new one\n"); | |
144 e = cast(aaA *) cast(void*) new void[aaA.sizeof + Value.sizeof + Property.sizeof]; | |
145 std.c.string.memcpy(e + 1, key, Value.sizeof); | |
146 e.hash = hash; | |
147 *pe = e; | |
148 | |
149 auto nodes = ++aa.a.nodes; | |
150 //printf("length = %d, nodes = %d\n", (*aa).length, nodes); | |
151 if (nodes > aalen * 4) | |
152 { | |
153 _aaRehash(aa, typeid(Value)); | |
154 } | |
155 | |
156 Lret: | |
157 return cast(Property*)(cast(void *)(e + 1) + Value.sizeof); | |
158 } | |
159 | |
160 /************************************ | |
161 * Alternate In() with precomputed values. | |
162 */ | |
163 | |
164 Property* _aaInY(hash_t hash, Property[Value] bb, Value* key) | |
165 { | |
166 size_t i; | |
167 AA aa = *cast(AA*)&bb; | |
168 | |
169 //printf("_aaIn(), aa.length = %d, .ptr = %x\n", aa.length, cast(uint)aa.ptr); | |
170 if (aa.a && aa.a.b.length) | |
171 { | |
172 //printf("hash = %d\n", hash); | |
173 i = hash % aa.a.b.length; | |
174 auto e = aa.a.b[i]; | |
175 while (e != null) | |
176 { | |
177 if (hash == e.hash) | |
178 { | |
179 Value* v = cast(Value*)(e + 1); | |
180 if (key.vtype == V_NUMBER && v.vtype == V_NUMBER && | |
181 key.number == v.number) | |
182 goto Lfound; | |
183 auto c = key.opCmp(v); | |
184 if (c == 0) | |
185 { | |
186 Lfound: | |
187 return cast(Property*)(cast(void *)(e + 1) + Value.sizeof); | |
188 } | |
189 else | |
190 e = (c < 0) ? e.left : e.right; | |
191 } | |
192 else | |
193 e = (hash < e.hash) ? e.left : e.right; | |
194 } | |
195 } | |
196 | |
197 // Not found | |
198 return null; | |
199 } | |
200 } | |
201 | |
202 /*********************************** PropTable *********************/ | |
203 | |
204 struct PropTable | |
205 { | |
206 Property[Value] table; | |
207 PropTable* previous; | |
208 | |
209 int opApply(int delegate(inout Property) dg) | |
210 { int result; | |
211 | |
212 foreach (inout Property p; table) | |
213 { | |
214 result = dg(p); | |
215 if (result) | |
216 break; | |
217 } | |
218 return result; | |
219 } | |
220 | |
221 int opApply(int delegate(inout Value, inout Property) dg) | |
222 { int result; | |
223 | |
224 foreach (Value key, inout Property p; table) | |
225 { | |
226 result = dg(key, p); | |
227 if (result) | |
228 break; | |
229 } | |
230 return result; | |
231 } | |
232 | |
233 /******************************* | |
234 * Look up name and get its corresponding Property. | |
235 * Return null if not found. | |
236 */ | |
237 | |
238 Property *getProperty(d_string name) | |
239 { | |
240 Value* v; | |
241 Property *p; | |
242 | |
243 v = get(name, Value.calcHash(name)); | |
244 if (!v) | |
245 return null; | |
246 | |
247 // Work backwards from &p->value to p | |
248 p = cast(Property *)(cast(char *)v - uint.sizeof /*Property.value.offsetof*/); | |
249 | |
250 return p; | |
251 } | |
252 | |
253 Value* get(Value* key, hash_t hash) | |
254 { | |
255 uint i; | |
256 Property *p; | |
257 PropTable *t; | |
258 | |
259 //writefln("get(key = '%s', hash = x%x)", key.toString(), hash); | |
260 assert(key.toHash() == hash); | |
261 t = this; | |
262 do | |
263 { | |
264 //writefln("\tt = %x", cast(uint)t); | |
265 // p = *key in t.table; | |
266 p = _aaInY(hash, t.table, key); | |
267 | |
268 if (p) | |
269 { //writefln("\tfound"); | |
270 //p.value.dump(); | |
271 assert(&t.table[*key] == p); | |
272 //p.value.dump(); | |
273 return &p.value; | |
274 } | |
275 t = t.previous; | |
276 } while (t); | |
277 //writefln("\tnot found"); | |
278 return null; // not found | |
279 } | |
280 | |
281 Value* get(d_uint32 index) | |
282 { | |
283 //writefln("get(index = %d)", index); | |
284 Value key; | |
285 | |
286 key.putVnumber(index); | |
287 return get(&key, Value.calcHash(index)); | |
288 } | |
289 | |
290 Value* get(Identifier* id) | |
291 { | |
292 //writefln("get('%s', hash = x%x)", name, hash); | |
293 return get(&id.value, id.value.hash); | |
294 //return get(id.value.string, id.value.hash); | |
295 } | |
296 | |
297 Value* get(d_string name, hash_t hash) | |
298 { | |
299 //writefln("get('%s', hash = x%x)", name, hash); | |
300 Value key; | |
301 | |
302 key.putVstring(name); | |
303 return get(&key, hash); | |
304 } | |
305 | |
306 /******************************* | |
307 * Determine if property exists for this object. | |
308 * The enumerable flag means the DontEnum attribute cannot be set. | |
309 */ | |
310 | |
311 int hasownproperty(Value* key, int enumerable) | |
312 { | |
313 Property* p; | |
314 | |
315 p = *key in table; | |
316 return p && (!enumerable || !(p.attributes & DontEnum)); | |
317 } | |
318 | |
319 int hasproperty(Value* key) | |
320 { | |
321 return (*key in table) != null; | |
322 } | |
323 | |
324 int hasproperty(d_string name) | |
325 { | |
326 Value v; | |
327 | |
328 v.putVstring(name); | |
329 return hasproperty(&v); | |
330 } | |
331 | |
332 Value* put(Value* key, hash_t hash, Value* value, uint attributes) | |
333 { | |
334 Property* p; | |
335 | |
336 //writefln("put(key = %s, hash = x%x, value = %s, attributes = x%x)", key.toString(), hash, value.toString(), attributes); | |
337 //writefln("put(key = %s)", key.toString()); | |
338 // p = &table[*key]; | |
339 p = _aaGetY(hash, &table, key); | |
340 /+ | |
341 { | |
342 size_t i; | |
343 aaA *e; | |
344 aaA **pe; | |
345 aaA*[]* aa = cast(aaA*[]*)&table; | |
346 size_t aalen; | |
347 | |
348 aalen = (*aa).length; | |
349 if (!aalen) | |
350 { | |
351 alias aaA *pa; | |
352 | |
353 aalen = 97 + 1; | |
354 *aa = new pa[aalen]; | |
355 (*aa)[0] = cast(aaA *) cast(void*) new void[aaA.sizeof]; | |
356 } | |
357 | |
358 //printf("hash = %d\n", hash); | |
359 i = (hash % (aalen - 1)) + 1; | |
360 pe = &(*aa)[i]; | |
361 while ((e = *pe) != null) | |
362 { | |
363 if (hash == e.hash) | |
364 { | |
365 Value* v = cast(Value*)(e + 1); | |
366 if (key.vtype == V_NUMBER) | |
367 { if (v.vtype == V_NUMBER && key.number == v.number) | |
368 goto Lfound; | |
369 } | |
370 else if (key.vtype == V_STRING) | |
371 { if (v.vtype == V_STRING && key.string is v.string) | |
372 goto Lfound; | |
373 } | |
374 auto c = key.opCmp(v); | |
375 if (c == 0) | |
376 { | |
377 Lfound: | |
378 p = cast(Property*)(v + 1); | |
379 goto Lx; | |
380 } | |
381 pe = (c < 0) ? &e.left : &e.right; | |
382 } | |
383 else | |
384 pe = (hash < e.hash) ? &e.left : &e.right; | |
385 } | |
386 | |
387 // Not found, create new elem | |
388 //printf("\tcreate new one\n"); | |
389 e = cast(aaA *) cast(void*) new void[aaA.sizeof + Value.sizeof + Property.sizeof]; | |
390 memcpy(e + 1, key, Value.sizeof); | |
391 e.hash = hash; | |
392 *pe = e; | |
393 | |
394 uint nodes = ++(*aa)[0].nodes; | |
395 //printf("length = %d, nodes = %d\n", (*aa).length, nodes); | |
396 if (nodes > aalen * 4) | |
397 { | |
398 _aaRehash(aa, typeid(Value)); | |
399 } | |
400 | |
401 p = cast(Property*)(cast(void *)(e + 1) + Value.sizeof); | |
402 } | |
403 +/ | |
404 if (p.value.vtype != V_NONE) | |
405 { | |
406 Lx: | |
407 if (attributes & DontOverride || | |
408 p.attributes & ReadOnly) | |
409 { | |
410 if (p.attributes & KeyWord) | |
411 return null; | |
412 return &vundefined; | |
413 } | |
414 | |
415 PropTable* t = previous; | |
416 if (t) | |
417 { | |
418 do | |
419 { Property* q; | |
420 // q = *key in t.table; | |
421 q = _aaInY(hash, t.table, key); | |
422 if (q) | |
423 { | |
424 if (q.attributes & ReadOnly) | |
425 { p.attributes |= ReadOnly; | |
426 return &vundefined; | |
427 } | |
428 break; | |
429 } | |
430 t = t.previous; | |
431 } while (t); | |
432 } | |
433 | |
434 // Overwrite property with new value | |
435 Value.copy(&p.value, value); | |
436 p.attributes = (attributes & ~DontOverride) | (p.attributes & (DontDelete | DontEnum)); | |
437 return null; | |
438 } | |
439 | |
440 // Not in table; create new entry | |
441 | |
442 p.attributes = attributes & ~DontOverride; | |
443 Value.copy(&p.value, value); | |
444 assert(p.value == value); | |
445 | |
446 return null; // success | |
447 } | |
448 | |
449 Value* put(d_string name, Value* value, uint attributes) | |
450 { | |
451 Value key; | |
452 | |
453 key.putVstring(name); | |
454 | |
455 //writef("PropTable::put(%p, '%ls', hash = x%x)\n", this, d_string_ptr(name), key.toHash()); | |
456 return put(&key, Value.calcHash(name), value, attributes); | |
457 } | |
458 | |
459 Value* put(d_uint32 index, Value* value, uint attributes) | |
460 { | |
461 Value key; | |
462 | |
463 key.putVnumber(index); | |
464 | |
465 //writef("PropTable::put(%d)\n", index); | |
466 return put(&key, Value.calcHash(index), value, attributes); | |
467 } | |
468 | |
469 Value* put(d_uint32 index, d_string string, uint attributes) | |
470 { | |
471 Value key; | |
472 Value value; | |
473 | |
474 key.putVnumber(index); | |
475 value.putVstring(string); | |
476 | |
477 return put(&key, Value.calcHash(index), &value, attributes); | |
478 } | |
479 | |
480 int canput(Value* key, hash_t hash) | |
481 { | |
482 Property *p; | |
483 PropTable *t; | |
484 | |
485 t = this; | |
486 do | |
487 { | |
488 // p = *key in t.table; | |
489 p = _aaInY(hash, t.table, key); | |
490 if (p) | |
491 { return (p.attributes & ReadOnly) | |
492 ? false : true; | |
493 } | |
494 t = t.previous; | |
495 } while (t); | |
496 return true; // success | |
497 } | |
498 | |
499 int canput(d_string name) | |
500 { | |
501 Value v; | |
502 | |
503 v.putVstring(name); | |
504 | |
505 return canput(&v, v.toHash()); | |
506 } | |
507 | |
508 int del(Value* key) | |
509 { | |
510 Property *p; | |
511 | |
512 //writef("PropTable::del('%ls')\n", d_string_ptr(key.toString())); | |
513 p = *key in table; | |
514 if (p) | |
515 { | |
516 if (p.attributes & DontDelete) | |
517 return false; | |
518 table.remove(*key); | |
519 } | |
520 return true; // not found | |
521 } | |
522 | |
523 int del(d_string name) | |
524 { | |
525 Value v; | |
526 | |
527 v.putVstring(name); | |
528 | |
529 //writef("PropTable::del('%ls')\n", d_string_ptr(name)); | |
530 return del(&v); | |
531 } | |
532 | |
533 int del(d_uint32 index) | |
534 { | |
535 Value v; | |
536 | |
537 v.putVnumber(index); | |
538 | |
539 //writef("PropTable::del(%d)\n", index); | |
540 return del(&v); | |
541 } | |
542 } | |
543 | |
544 |