Mercurial > projects > dmdscript-tango
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmdscript_tango/property.d Sun Jan 24 12:34:47 2010 +0200 @@ -0,0 +1,544 @@ + +/* Digital Mars DMDScript source code. + * Copyright (c) 2000-2002 by Chromium Communications + * D version Copyright (c) 2004-2006 by Digital Mars + * All Rights Reserved + * written by Walter Bright + * www.digitalmars.com + * Use at your own risk. There is no warranty, express or implied. + * License for redistribution is by the GNU General Public License in gpl.txt. + * + * A binary, non-exclusive license for commercial use can be + * purchased from www.digitalmars.com/dscript/buy.html. + * + * DMDScript is implemented in the D Programming Language, + * www.digitalmars.com/d/ + * + * For a C++ implementation of DMDScript, including COM support, + * see www.digitalmars.com/dscript/cppscript.html. + */ + + +module dmdscript.property; + +import dmdscript.script; +import dmdscript.value; +import dmdscript.identifier; + +import std.c.string; + +// attribute flags +enum +{ + ReadOnly = 0x001, + DontEnum = 0x002, + DontDelete = 0x004, + Internal = 0x008, + Deleted = 0x010, + Locked = 0x020, + DontOverride = 0x040, + KeyWord = 0x080, + DebugFree = 0x100, // for debugging help + Instantiate = 0x200, // For COM named item namespace support +} + +struct Property +{ + uint attributes; + + Value value; +} + +extern (C) +{ + /* These functions are part of the internal implementation of Phobos + * associative arrays. It's faster to use them when we have precomputed + * values to use. + */ + + struct Array + { + int length; + void* ptr; + } + + struct aaA + { + aaA *left; + aaA *right; + hash_t hash; + /* key */ + /* value */ + } + + struct BB + { + aaA*[] b; + size_t nodes; // total number of aaA nodes + } + + struct AA + { + BB* a; + version (X86_64) + { + } + else + { + // This is here only to retain binary compatibility with the + // old way we did AA's. Should eventually be removed. + int reserved; + } + } + + long _aaRehash(AA* paa, TypeInfo keyti); + + /************************ + * Alternate Get() version + */ + + Property* _aaGetY(hash_t hash, Property[Value]* bb, Value* key) + { + aaA* e; + auto aa = cast(AA*)bb; + + if (!aa.a) + aa.a = new BB(); + + auto aalen = aa.a.b.length; + if (!aalen) + { + alias aaA *pa; + + aalen = 97; + aa.a.b = new pa[aalen]; + } + + //printf("hash = %d\n", hash); + size_t i = hash % aalen; + auto pe = &aa.a.b[i]; + while ((e = *pe) != null) + { + if (hash == e.hash) + { + Value* v = cast(Value*)(e + 1); + if (key.vtype == V_NUMBER) + { if (v.vtype == V_NUMBER && key.number == v.number) + goto Lret; + } + else if (key.vtype == V_STRING) + { if (v.vtype == V_STRING && key.string is v.string) + goto Lret; + } + auto c = key.opCmp(v); + if (c == 0) + goto Lret; + pe = (c < 0) ? &e.left : &e.right; + } + else + pe = (hash < e.hash) ? &e.left : &e.right; + } + + // Not found, create new elem + //printf("\tcreate new one\n"); + e = cast(aaA *) cast(void*) new void[aaA.sizeof + Value.sizeof + Property.sizeof]; + std.c.string.memcpy(e + 1, key, Value.sizeof); + e.hash = hash; + *pe = e; + + auto nodes = ++aa.a.nodes; + //printf("length = %d, nodes = %d\n", (*aa).length, nodes); + if (nodes > aalen * 4) + { + _aaRehash(aa, typeid(Value)); + } + + Lret: + return cast(Property*)(cast(void *)(e + 1) + Value.sizeof); + } + + /************************************ + * Alternate In() with precomputed values. + */ + + Property* _aaInY(hash_t hash, Property[Value] bb, Value* key) + { + size_t i; + AA aa = *cast(AA*)&bb; + + //printf("_aaIn(), aa.length = %d, .ptr = %x\n", aa.length, cast(uint)aa.ptr); + if (aa.a && aa.a.b.length) + { + //printf("hash = %d\n", hash); + i = hash % aa.a.b.length; + auto e = aa.a.b[i]; + while (e != null) + { + if (hash == e.hash) + { + Value* v = cast(Value*)(e + 1); + if (key.vtype == V_NUMBER && v.vtype == V_NUMBER && + key.number == v.number) + goto Lfound; + auto c = key.opCmp(v); + if (c == 0) + { + Lfound: + return cast(Property*)(cast(void *)(e + 1) + Value.sizeof); + } + else + e = (c < 0) ? e.left : e.right; + } + else + e = (hash < e.hash) ? e.left : e.right; + } + } + + // Not found + return null; + } +} + +/*********************************** PropTable *********************/ + +struct PropTable +{ + Property[Value] table; + PropTable* previous; + + int opApply(int delegate(inout Property) dg) + { int result; + + foreach (inout Property p; table) + { + result = dg(p); + if (result) + break; + } + return result; + } + + int opApply(int delegate(inout Value, inout Property) dg) + { int result; + + foreach (Value key, inout Property p; table) + { + result = dg(key, p); + if (result) + break; + } + return result; + } + + /******************************* + * Look up name and get its corresponding Property. + * Return null if not found. + */ + + Property *getProperty(d_string name) + { + Value* v; + Property *p; + + v = get(name, Value.calcHash(name)); + if (!v) + return null; + + // Work backwards from &p->value to p + p = cast(Property *)(cast(char *)v - uint.sizeof /*Property.value.offsetof*/); + + return p; + } + + Value* get(Value* key, hash_t hash) + { + uint i; + Property *p; + PropTable *t; + + //writefln("get(key = '%s', hash = x%x)", key.toString(), hash); + assert(key.toHash() == hash); + t = this; + do + { + //writefln("\tt = %x", cast(uint)t); +// p = *key in t.table; + p = _aaInY(hash, t.table, key); + + if (p) + { //writefln("\tfound"); + //p.value.dump(); + assert(&t.table[*key] == p); + //p.value.dump(); + return &p.value; + } + t = t.previous; + } while (t); + //writefln("\tnot found"); + return null; // not found + } + + Value* get(d_uint32 index) + { + //writefln("get(index = %d)", index); + Value key; + + key.putVnumber(index); + return get(&key, Value.calcHash(index)); + } + + Value* get(Identifier* id) + { + //writefln("get('%s', hash = x%x)", name, hash); + return get(&id.value, id.value.hash); + //return get(id.value.string, id.value.hash); + } + + Value* get(d_string name, hash_t hash) + { + //writefln("get('%s', hash = x%x)", name, hash); + Value key; + + key.putVstring(name); + return get(&key, hash); + } + + /******************************* + * Determine if property exists for this object. + * The enumerable flag means the DontEnum attribute cannot be set. + */ + + int hasownproperty(Value* key, int enumerable) + { + Property* p; + + p = *key in table; + return p && (!enumerable || !(p.attributes & DontEnum)); + } + + int hasproperty(Value* key) + { + return (*key in table) != null; + } + + int hasproperty(d_string name) + { + Value v; + + v.putVstring(name); + return hasproperty(&v); + } + + Value* put(Value* key, hash_t hash, Value* value, uint attributes) + { + Property* p; + + //writefln("put(key = %s, hash = x%x, value = %s, attributes = x%x)", key.toString(), hash, value.toString(), attributes); + //writefln("put(key = %s)", key.toString()); +// p = &table[*key]; + p = _aaGetY(hash, &table, key); +/+ + { + size_t i; + aaA *e; + aaA **pe; + aaA*[]* aa = cast(aaA*[]*)&table; + size_t aalen; + + aalen = (*aa).length; + if (!aalen) + { + alias aaA *pa; + + aalen = 97 + 1; + *aa = new pa[aalen]; + (*aa)[0] = cast(aaA *) cast(void*) new void[aaA.sizeof]; + } + + //printf("hash = %d\n", hash); + i = (hash % (aalen - 1)) + 1; + pe = &(*aa)[i]; + while ((e = *pe) != null) + { + if (hash == e.hash) + { + Value* v = cast(Value*)(e + 1); + if (key.vtype == V_NUMBER) + { if (v.vtype == V_NUMBER && key.number == v.number) + goto Lfound; + } + else if (key.vtype == V_STRING) + { if (v.vtype == V_STRING && key.string is v.string) + goto Lfound; + } + auto c = key.opCmp(v); + if (c == 0) + { + Lfound: + p = cast(Property*)(v + 1); + goto Lx; + } + pe = (c < 0) ? &e.left : &e.right; + } + else + pe = (hash < e.hash) ? &e.left : &e.right; + } + + // Not found, create new elem + //printf("\tcreate new one\n"); + e = cast(aaA *) cast(void*) new void[aaA.sizeof + Value.sizeof + Property.sizeof]; + memcpy(e + 1, key, Value.sizeof); + e.hash = hash; + *pe = e; + + uint nodes = ++(*aa)[0].nodes; + //printf("length = %d, nodes = %d\n", (*aa).length, nodes); + if (nodes > aalen * 4) + { + _aaRehash(aa, typeid(Value)); + } + + p = cast(Property*)(cast(void *)(e + 1) + Value.sizeof); + } ++/ + if (p.value.vtype != V_NONE) + { + Lx: + if (attributes & DontOverride || + p.attributes & ReadOnly) + { + if (p.attributes & KeyWord) + return null; + return &vundefined; + } + + PropTable* t = previous; + if (t) + { + do + { Property* q; + // q = *key in t.table; + q = _aaInY(hash, t.table, key); + if (q) + { + if (q.attributes & ReadOnly) + { p.attributes |= ReadOnly; + return &vundefined; + } + break; + } + t = t.previous; + } while (t); + } + + // Overwrite property with new value + Value.copy(&p.value, value); + p.attributes = (attributes & ~DontOverride) | (p.attributes & (DontDelete | DontEnum)); + return null; + } + + // Not in table; create new entry + + p.attributes = attributes & ~DontOverride; + Value.copy(&p.value, value); + assert(p.value == value); + + return null; // success + } + + Value* put(d_string name, Value* value, uint attributes) + { + Value key; + + key.putVstring(name); + + //writef("PropTable::put(%p, '%ls', hash = x%x)\n", this, d_string_ptr(name), key.toHash()); + return put(&key, Value.calcHash(name), value, attributes); + } + + Value* put(d_uint32 index, Value* value, uint attributes) + { + Value key; + + key.putVnumber(index); + + //writef("PropTable::put(%d)\n", index); + return put(&key, Value.calcHash(index), value, attributes); + } + + Value* put(d_uint32 index, d_string string, uint attributes) + { + Value key; + Value value; + + key.putVnumber(index); + value.putVstring(string); + + return put(&key, Value.calcHash(index), &value, attributes); + } + + int canput(Value* key, hash_t hash) + { + Property *p; + PropTable *t; + + t = this; + do + { +// p = *key in t.table; + p = _aaInY(hash, t.table, key); + if (p) + { return (p.attributes & ReadOnly) + ? false : true; + } + t = t.previous; + } while (t); + return true; // success + } + + int canput(d_string name) + { + Value v; + + v.putVstring(name); + + return canput(&v, v.toHash()); + } + + int del(Value* key) + { + Property *p; + + //writef("PropTable::del('%ls')\n", d_string_ptr(key.toString())); + p = *key in table; + if (p) + { + if (p.attributes & DontDelete) + return false; + table.remove(*key); + } + return true; // not found + } + + int del(d_string name) + { + Value v; + + v.putVstring(name); + + //writef("PropTable::del('%ls')\n", d_string_ptr(name)); + return del(&v); + } + + int del(d_uint32 index) + { + Value v; + + v.putVnumber(index); + + //writef("PropTable::del(%d)\n", index); + return del(&v); + } +} + +