view dmdscript_tango/property.d @ 4:6d905019f7bf

some changes
author saaadel
date Thu, 28 Jan 2010 21:23:27 +0200
parents 8363a4bf6a8f
children
line wrap: on
line source


/* 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_tango.property;

import dmdscript_tango.script;
import dmdscript_tango.value;
import dmdscript_tango.identifier;

//import std.c.string;
import tango.stdc.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];
	tango.stdc.string.memcpy(e + 1, key, Value.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);
    }
}