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