
module object;

extern (C)
{   int printf(char *, ...);
    int memcmp(void *, void *, size_t);
}

alias bit bool;

version (AMD64)
{
    alias ulong size_t;
    alias long ptrdiff_t;
}
else
{
    alias uint size_t;
    alias int ptrdiff_t;
}

class Object
{
    void print()
    {
	printf("%.*s\n", toString());
    }

    char[] toString()
    {
	return this.classinfo.name;
    }

    uint toHash()
    {
	// BUG: this prevents a compacting GC from working, needs to be fixed
	return cast(uint)cast(void *)this;
    }

    int opCmp(Object o)
    {
	// BUG: this prevents a compacting GC from working, needs to be fixed
	return cast(int)cast(void *)this - cast(int)cast(void *)o;
    }

    int opEquals(Object o)
    {
	return this is o;
    }
}

struct Interface
{
    ClassInfo classinfo;
    void *[] vtbl;
    int offset;			// offset to Interface 'this' from Object 'this'
}

class ClassInfo : Object
{
    byte[] init;		// class static initializer
    char[] name;		// class name
    void *[] vtbl;		// virtual function pointer table
    Interface[] interfaces;
    ClassInfo base;
    void *destructor;
    void (*classInvariant)(Object);
    uint flags;
    //	1:			// IUnknown
    void *deallocator;
}

private import std.string;

class TypeInfo
{
    uint toHash()
    {	uint hash;

	foreach (char c; this.classinfo.name)
	    hash = hash * 9 + c;
	return hash;
    }

    int opCmp(Object o)
    {
	return std.string.cmp(this.classinfo.name, o.classinfo.name);
    }

    int opEquals(Object o)
    {
	/* TypeInfo instances are singletons, but duplicates can exist
	 * across DLL's. Therefore, comparing for a name match is
	 * sufficient.
	 */
	return this is o || this.classinfo.name == o.classinfo.name;
    }

    uint getHash(void *p) { return cast(uint)p; }
    int equals(void *p1, void *p2) { return p1 == p2; }
    int compare(void *p1, void *p2) { return 0; }
    int tsize() { return 0; }
    void swap(void *p1, void *p2)
    {
	int i;
	int n = tsize();
	for (i = 0; i < n; i++)
	{   byte t;

	    t = (cast(byte *)p1)[i];
	    (cast(byte *)p1)[i] = (cast(byte *)p2)[i];
	    (cast(byte *)p2)[i] = t;
	}
    }
}

class TypeInfo_Typedef : TypeInfo
{
    uint getHash(void *p) { return base.getHash(p); }
    int equals(void *p1, void *p2) { return base.equals(p1, p2); }
    int compare(void *p1, void *p2) { return base.compare(p1, p2); }
    int tsize() { return base.tsize(); }
    void swap(void *p1, void *p2) { return base.swap(p1, p2); }

    TypeInfo base;
}

class TypeInfo_Class : TypeInfo
{
    char[] toString() { return info.name; }

    uint getHash(void *p)
    {
	Object o = *cast(Object*)p;
	assert(o);
	return o.toHash();
    }

    int equals(void *p1, void *p2)
    {
	Object o1 = *cast(Object*)p1;
	Object o2 = *cast(Object*)p2;

	return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
    }

    int compare(void *p1, void *p2)
    {
	Object o1 = *cast(Object*)p1;
	Object o2 = *cast(Object*)p2;
	int c = 0;

	// Regard null references as always being "less than"
	if (o1 != o2)
	{
	    if (o1)
	    {	if (!o2)
		    c = 1;
		else
		    c = o1.opCmp(o2);
	    }
	    else
		c = -1;
	}
	return c;
    }

    int tsize()
    {
	return Object.sizeof;
    }

    ClassInfo info;
}

class TypeInfo_Struct : TypeInfo
{
    char[] toString() { return name; }

    uint getHash(void *p)
    {	uint h;

	assert(p);
	if (xtoHash)
	    h = (*xtoHash)(p);
	else
	{
	    // A sorry hash algorithm.
	    // Should use the one for strings.
	    // BUG: relies on the GC not moving objects
	    for (size_t i = 0; i < xsize; i++)
	    {	h = h * 9 + *cast(ubyte*)p;
		p++;
	    }
	}
	return h;
    }

    int equals(void *p2, void *p1)
    {	int c;

	if (p1 == p2)
	    c = 1;
	else if (!p1 || !p2)
	    c = 0;
	else if (xopEquals)
	    c = (*xopEquals)(p1, p2);
	else
	    // BUG: relies on the GC not moving objects
	    c = (memcmp(p1, p2, xsize) == 0);
	return c;
    }

    int compare(void *p2, void *p1)
    {
	int c = 0;

	// Regard null references as always being "less than"
	if (p1 != p2)
	{
	    if (p1)
	    {	if (!p2)
		    c = 1;
		else if (xopCmp)
		    c = (*xopCmp)(p1, p2);
		else
		    // BUG: relies on the GC not moving objects
		    c = memcmp(p1, p2, xsize);
	    }
	    else
		c = -1;
	}
	return c;
    }

    int tsize()
    {
	return xsize;
    }

    char[] name;
    uint xsize;

    uint function(void*) xtoHash;
    int function(void*,void*) xopEquals;
    int function(void*,void*) xopCmp;
}

class Exception : Object
{
    char[] msg;

    this(char[] msg)
    {
	this.msg = msg;
    }

    void print()
    {
	printf("%.*s\n", msg);
    }

    char[] toString() { return msg; }
}

class Error : Exception
{
    Error next;

    this(char[] msg)
    {
	super(msg);
    }

    this(char[] msg, Error next)
    {
	super(msg);
	this.next = next;
    }
}

