grendel-1.0.0a7/backup/
grendel-1.0.0a7/bin/
grendel-1.0.0a7/boards/
grendel-1.0.0a7/clans/
grendel-1.0.0a7/documentation/todo/
grendel-1.0.0a7/help/
grendel-1.0.0a7/logs/
grendel-1.0.0a7/players/
grendel-1.0.0a7/progs/
grendel-1.0.0a7/races/
grendel-1.0.0a7/src/contrib/
grendel-1.0.0a7/src/modules/speller/
grendel-1.0.0a7/src/modules/status/
grendel-1.0.0a7/src/tests/
grendel-1.0.0a7/src/tests/dunit/
{
	Summary:
		Collection of common datastructures
		
  ##	$Id: dtypes.pas,v 1.14 2004/03/26 17:00:15 druid Exp $
}

unit dtypes;

interface


uses
	Variants,
	Classes,
	SysUtils;


{$M+}
type
	{
		Container class for strings
	}
	GString = class
	private    
		_value : string;

	published
		constructor Create(const value : string);

		property value : string read _value write _value;		{ The string value }
	end;

	{
		Container class for integers
	}
	GInteger = class
	private
		_value : integer;

	published
		constructor Create(const value : integer);

		property value : integer read _value write _value;	{ The integer value }
	end;

	{
		Container class for bitvectors
	}
	GBitVector = class
	private
		_value : cardinal;

	published
		constructor Create(const value : cardinal);

		function isBitSet(const bit : cardinal) : boolean;
		procedure setBit(const bit : cardinal);
		procedure removeBit(const bit : cardinal);

		property value : cardinal read _value write _value;	{ The integer value (bitvector) }
	end;

	{
		Base class for list nodes
	}
	GListNode = class
	private
		_prev : GListNode; 				{ Pointer to previous node in list }
		_next : GListNode;					{ Pointer to next node in list }
		_element : TObject;				{ Pointer to element }

	public
		property prev : GListNode read _prev write _prev;
		property next : GListNode read _next write _next;

	published
		constructor Create(e : pointer; p, n : GListNode);

		property element : TObject read _element write _element;
	end;

	{
		Abstract base class for iterators
	}
	GIterator = class
	published
		function getCurrent() : TObject; virtual; abstract;	{ Abstract getCurrent() }
		function hasNext() : boolean; virtual; abstract;		{ Abstract hasNext() }
		function next() : TObject; virtual; abstract;				{ Abstract next() }
	end;

	{
		Doubled linked list
	}
	GDLinkedList = class
	private
		_size : integer;						
		_serial : integer;
		_head : GListNode;					{ Pointer to head of list }
		_tail : GListnode;					{ Pointer to tail of list }
		_owns : boolean;
		
	public
		procedure remove(node : GListNode); overload;

	published
		function insertLast(element : pointer) : GListNode;
		function insertFirst(element : pointer) : GListNode;
		function insertAfter(tn : GListNode; element : pointer) : GListNode;
		function insertBefore(tn : GListNode; element : pointer) : GListNode;

		procedure add(element : TObject);
		procedure remove(element : TObject); overload;
		procedure clear();

		function size() : integer;

		function iterator() : GIterator;

		constructor Create();
		destructor Destroy(); override;

		property head : GListNode read _head;
		property tail : GListNode read _tail;
		
		property ownsObjects : boolean read _owns write _owns;
	end;

	{
		Array to store a set of prime numbers
	}
	GPrimes = array of integer;

	{
		Array to store a set of linked lists
	}
	GDLinkedListArray = array of GDLinkedList;

	{
		Definition of hash function
	}
	GHASH_FUNC = function(size, prime : integer; const key : string) : integer;

	{
		Container for hash elements
	}
	GHashValue = class
	private
		_key : variant;				{ Hash key }
		_refcount : integer;		{ Reference count }
		_value : TObject;			{ Element }

	published
		constructor Create(key : variant; value : TObject);

		procedure addRef();
		procedure release();

		property key : variant read _key;
		property refcount : integer read _refcount;
		property value : TObject read _value;
	end;

	{
		Hash table class, loosely based on the Java2 hashing classes
	}
	GHashTable = class
	private
		_owns : boolean;

		hashprime : integer;
		hashsize : integer;										{ Size of hash table }
		bucketList : GDLinkedListArray;				{ Array of double linked lists }
		hashFunc : GHASH_FUNC;

		function getBucket(index : integer) : GDLinkedList;
		function _get(key : variant) : GHashValue;
		function findPrimes(n : integer) : GPrimes;

	published
		procedure clear();

		function isEmpty() : boolean;
		function size() : integer;

		function iterator() : GIterator;

		function get(key : variant) : TObject;
		procedure put(key : variant; value : TObject);
		procedure remove(key : variant);

		function getHash(key : variant) : integer;
		procedure setHashFunc(func : GHASH_FUNC);

		procedure hashStats(); virtual;

		constructor Create(size : integer);
		destructor Destroy(); override;

		property ownsObjects : boolean read _owns write _owns;

	public
		property item[key : variant] : TObject read get write put; default;		{ Provides overloaded access to hash table }  
		property buckets[index : integer] : GDLinkedList read getBucket;
		property bucketcount : integer read hashsize;
	end;
	
	{
		Singleton class
	}
	GSingleton = class
	public
		class function NewInstance : TObject; override;
		procedure FreeInstance; override;
		
		{ Actual constructor, override this one instead of TObject.Create() }
		constructor actualCreate(); virtual;
		
		{	Actual destructor, override this one instead of TObject.Destroy() }
		destructor actualDestroy(); virtual;
	end;
{$M-}    


var
	{	Global string hash table }
  str_hash : GHashTable;
  

function hash_string(const src : string) : PString; overload;
function hash_string(src : PString) : PString; overload;

procedure unhash_string(var src : PString);

function md5Hash(size, prime : integer; const key : string) : integer;
function defaultHash(size, prime : integer; const key : string) : integer;
function firstHash(size, prime : integer; const key : string) : integer;
function sortedHash(size, prime : integer; const key : string) : integer;


implementation


uses
	md5;


type
		{
			Iterator class for double linked lists
		}
    GDLinkedListIterator = class(GIterator)
    private
      current : GListNode;

    published
      constructor Create(list : GDLinkedList);

			function getCurrent() : TObject; override;
      function hasNext() : boolean; override;
      function next() : TObject; override;
    end;

		{
			Iterator class for hash tables
		}
    GHashTableIterator = class(GIterator)
    private
      tbl : GHashTable;
      cursor : integer;
      current : GListNode;

    published
      constructor Create(table : GHashTable);

			function getCurrent() : TObject; override;
      function hasNext() : boolean; override;
      function next() : TObject; override;
    end;
    
    		{
    			Singleton info class
    		}
    		GSingletonInfo = class
    		private
    			_instanceType : TClass;
    			_instance : TObject;
    			_refcount : integer;
    			
    		published
    			property instanceType : TClass read _instanceType write _instanceType;
    			property instance : TObject read _instance write _instance;
    			property refcount : integer read _refcount write _refcount;	
    		end;
    		
		{
			Singleton manager class
		}
		GSingletonManager = class
		private
			infoList : TList;
			
		public
			constructor Create();
			destructor Destroy(); override;
			
		published
			procedure addInstance(instance : TObject);
			function findInstance(classType : TClass) : TObject;
			function removeInstance(classType : TClass) : boolean;
		end;
				


{
	Size of global string hash table
}
const STR_HASH_SIZE = 1024;

var
  { Instance of singleton manager }
  singletonManager : GSingletonManager;


{
	Summary:
		GString constructor
}
constructor GString.Create(const value : string);
begin
  inherited Create();

  _value := value;
end;


{
	Summary:
		GInteger constructor
}
constructor GInteger.Create(const value : integer);
begin
  inherited Create();

  _value := value;
end;


{
	Summary:
		GBitVector constructor
}
constructor GBitVector.Create(const value : cardinal);
begin
  inherited Create();

  _value := value;
end;

{
	Summary:
		Check wether bit is set
}
function GBitVector.isBitSet(const bit : cardinal) : boolean;
begin
  Result := ((_value and bit) = bit);
end;

{
	Summary:
		Set bit
}
procedure GBitVector.setBit(const bit : cardinal);
begin
  _value := _value or bit;
end;

{
	Summary:
		Un-set (remove) bit
}
procedure GBitVector.removeBit(const bit : cardinal);
begin
  if (isBitSet(bit)) then
    dec(_value, bit);
end;


{
	Summary:
		GListNode constructor
}
constructor GListNode.Create(e : pointer; p, n : GListNode);
begin
  inherited Create;

  element := e;
  next := n;
  prev := p;
end;

{
	Summary:
		GDLinkedListIterator constructor
}
constructor GDLinkedListIterator.Create(list : GDLinkedList);
begin
  inherited Create();

  current := list.head;
end;

{
	Summary:
		Get current element in list
}
function GDLinkedListIterator.getCurrent() : TObject;
begin
	if (current <> nil) then
		Result := current.element
	else
		Result := nil;
end;

{
	Summary:
		Check availability of next element
}
function GDLinkedListIterator.hasNext() : boolean;
begin
  Result := (current <> nil);
end;

{
	Summary:
		Get next element in list (if available)	
}
function GDLinkedListIterator.next() : TObject;
begin
  Result := nil;

  if (hasNext()) then
    begin
    Result := current.element;

    current := current.next;
    end;
end;


{
	Summary:
		GHashTableIterator constructor
}
constructor GHashTableIterator.Create(table : GHashTable);
begin
  inherited Create();

  tbl := table;

  current := nil;
  cursor := 0;

  while (current = nil) and (cursor < tbl.hashSize) do
    begin
    if (tbl.bucketlist[cursor].head <> nil) then
      begin
      current := tbl.bucketList[cursor].head;
      break;
      end;
      
    inc(cursor);
    end;
end;

{
	Summary:
		Get current element in list
}
function GHashTableIterator.getCurrent() : TObject;
begin
	Result := GHashValue(current.element).value;
end;

{
	Summary:
		Check availability of next element
}
function GHashTableIterator.hasNext() : boolean;
begin
  Result := (current <> nil);
end;

{
	Summary:
		Get next element in list (if available)	
}
function GHashTableIterator.next() : TObject;
begin
  Result := nil;

  if (hasNext()) then
    begin
    Result := GHashValue(current.element).value;

    current := current.next;

    if (current = nil) then
      begin
      inc(cursor);

      while (current = nil) and (cursor < tbl.hashSize) do
        begin
        if (tbl.bucketlist[cursor].head <> nil) then
          begin
          current := tbl.bucketList[cursor].head;
          break;
          end;
      
        inc(cursor);
        end;
      end;
    end;
end;


{
	Summary:
		GDLinkedList constructor
}
constructor GDLinkedList.Create();
begin
  inherited Create();

	_owns := true;
	
  _head := nil;
  _tail := nil;
  _size := 0;
  _serial := 1;
end;

{
	Summary:
		GDLinkedList destructor
}
destructor GDLinkedList.Destroy();
begin
  inherited Destroy();
end;

{
	Summary:
		Add element to tail of list
}
function GDLinkedList.insertLast(element : pointer) : GListNode;
var
	node : GListNode;
begin
	node := GListNode.Create(element, _tail, nil);

	if (_head = nil) then
		_head := node
	else
		_tail.next := node;

	_tail := node;

	Result := node;

	inc(_size);
	inc(_serial);
end;

{
	Summary:
		Add element to tail of list
}
function GDLinkedList.insertFirst(element : pointer) : GListNode;
var
	node : GListNode;
begin
	node := GListNode.Create(element, nil, _head);
	
	if (_head <> nil) then
		_head.prev := node;

	_head := node;

	Result := node;

	inc(_size);
	inc(_serial);
end;

{
	Summary:
		Short for insertLast()
}
procedure GDLinkedList.add(element : TObject);
begin
	insertLast(element);
end;

{
	Summary:
		Add element after another element
}
function GDLinkedList.insertAfter(tn : GListNode; element : pointer) : GListNode;
var
   node : GListNode;
begin
	node := GListNode.Create(element, tn, tn.next);

	if (tn.next <> nil) then
		tn.next.prev := node;

	tn.next := node;

	if (_tail = tn) then
		_tail := node;

	Result := node;

	inc(_size);
	inc(_serial);
end;

{
	Summary:
		Add element before another element
}
function GDLinkedList.insertBefore(tn : GListNode; element : pointer) : GListNode;
var
   node : GListNode;
begin
	node := GListNode.Create(element, tn.prev, tn);

	if (tn.prev <> nil) then
		tn.prev.next := node;

	tn.prev := node;

	if (_head = tn) then
		_head := node;

	Result := node;

	inc(_size);
	inc(_serial);
end;

{
	Summary:
		Find and remove element from list
}
procedure GDLinkedList.remove(element : TObject);
var
  node : GListNode;
begin
  node := head;
  
  while (node <> nil) do
    begin
    if (node.element = element) then
      begin
      remove(node);
      exit;
      end;
      
    node := node.next;
    end;
end;

{
	Summary:
		Remove node from list
}
procedure GDLinkedList.remove(node : GListNode);
begin
	if (node.prev = nil) then
		_head := node.next
	else
		node.prev.next := node.next;

	if (node.next = nil) then
		_tail := node.prev
	else
		node.next.prev := node.prev;

	dec(_size);
	inc(_serial);
	node.Free();
end;

{
	Summary:
		Get size of list
}
function GDLinkedList.size() : integer;
begin
  Result := _size;
end;

{
	Summary:
		Remove all items from list, if ownsObject is true items are freed as well
}
procedure GDLinkedList.clear();
var
   node : GListNode;
begin
  while (true) do
    begin
    node := _tail;

    if (node = nil) then
      exit;

		if (ownsObjects) then
    	TObject(node.element).Free;

    remove(node);
    end;
end;

{
	Summary:
		Get iterator for the list
}
function GDLinkedList.iterator() : GIterator;
begin
  Result := GDLinkedListIterator.Create(Self);
end;


{ 
	Summary:
		MD5 hashing function
}
function md5Hash(size, prime : integer; const key : string) : integer;
var
  md : MD5Digest;
  val : integer;
  i : integer;
begin
  md := MD5String(key);
  
  val := 0;
  
  for i := 0 to 7 do
    val := val + (md[i] shl i);
  
  Result := abs(val) mod size;
end;

{ 
	Summary:
		Default (string) hashing function
}
function defaultHash(size, prime : integer; const key : string) : integer;
var
   i : integer;
   val : integer;
begin
  val := 0;

  {$Q-}
  for i := 1 to length(key) do
    val := val * prime + byte(key[i]);

  Result := abs(val) mod size;
end;

{ 
	Summary:
		Alternative string hashing function, only uses first character in string
}
function firstHash(size, prime : integer; const key : string) : integer;
begin
  if (length(key) >= 1) then
    Result := (byte(key[1]) * prime) mod size
  else
    Result := 0;
end;

{ 
	Summary:
		Alternative string hashing function, sorts linearly on first character in string
}
function sortedHash(size, prime : integer; const key : string) : integer;
begin
  if (length(key) >= 1) then
    Result := (byte(key[1]) * size) div 256
  else
    Result := 0;
end;

{
	Summary:
		Get an array of prime numbers
}
function GHashTable.findPrimes(n : integer) : GPrimes;
var
   i, j : integer;
   limit : double;
   numbers : GPrimes;
   numberpool : array of boolean;
begin
  setlength(numberpool, n);

  for i := 2 to n - 1 do
    numberpool[i] := true;

  limit := sqrt(n);

  j := 2;

  i := j + j;

  while (i < n) do
    begin
    numberpool[i] := false;
    i := i + j;
    end;

  j := 3;

  while (j <= limit) do
    begin
    if (numberpool[j] = true) then
      begin
      i := j + j;

      while (i < n) do
        begin
        numberpool[i] := false;

        i := i + j;
        end;
      end;

    j := j + 2;
    end;

  j := 0;

  for i := 0 to n - 1 do
    begin
    if (numberpool[i]) then
      begin
      setLength(numbers, j + 1);
      numbers[j] := i;
      j := j + 1;
      end;
    end;

  Result := numbers;
end;

{
	Summary:
		GHashValue constructor
}
constructor GHashValue.Create(key : variant; value : TObject);
begin
	inherited Create();
	
	_key := key;
	_value := value;
	_refcount := 1;
end;

{
	Summary:
		Increases the reference count by one
}
procedure GHashValue.addRef();
begin
	inc(_refcount);
end;

{
	Summary:
		Decreases the reference count by one
}
procedure GHashValue.release();
begin
	dec(_refcount);
end;

{
	Summary:
		Get hash-value for a key
	
	Remarks:
		Uses static hash function for integers
}
function GHashTable.getHash(key : variant) : integer;
{$O-}
begin
  if (varType(key) = varString) then
    Result := hashFunc(hashsize, hashprime, key)
  else
  if (varType(key) in [varSmallint,varInteger,varShortInt,varByte,varWord,varLongWord]) then
    Result := (integer(key) * hashprime) mod hashsize
  else
  { shouldn't be here }
  	raise Exception.Create('Impossible to determine hashkey for unknown variant type ' + VarTypeAsText(VarType(key)));
  
  // final safeguard against indices < 0
  Result := abs(Result);
end;

{
	Summary:
		Set hash function
}
procedure GHashTable.setHashFunc(func : GHASH_FUNC);
begin
  hashFunc := func;
end;

{
	Summary:
		Retrieves bucket at given index
}
function GHashTable.getBucket(index : integer) : GDLinkedList;
begin
	if (index < 0) or (index >= length(bucketList)) then
		begin
		raise Exception.Create('Index (' + IntToStr(index) + ') out of bounds');
		end
	else	
		Result := bucketList[index];
end;

{
	Summary:
		Get hash object corresponding with key
}
function GHashTable._get(key : variant) : GHashValue;
var
  hash : integer;
  node : GListNode;
begin
  Result := nil;
  hash := getHash(key);
  
	try
  	node := bucketList[hash].head;
  except
  	node := nil;
  end;

  while (node <> nil) do
    begin
    if (GHashValue(node.element).key = key) then
      begin
      Result := GHashValue(node.element);
      break;
      end;

    node := node.next;
    end;
end;

{
	Summary:
		Get element corresponding with key
}
function GHashTable.get(key : variant) : TObject;
var
  hv : GHashValue;
begin
  Result := nil;

  hv := _get(key);

  if (hv <> nil) then
    Result := hv.value;
end;

{
	Summary:
		Put element in hash table
}
procedure GHashTable.put(key : variant; value : TObject);
var
   hash : integer;
   hv : GHashValue;
begin
	if (value = nil) then
		begin
		remove(key);
		end
	else
		begin
		hv := _get(key);

		if (hv <> nil) then
			begin
			hv.addRef();
			end
		else
			begin
			hash := getHash(key);

			hv := GHashValue.Create(key, value);

			bucketList[hash].insertLast(hv);
			end;
		end;
end;

{
	Summary:
		Remove key from hash table
}
procedure GHashTable.remove(key : variant);
var
  hash : integer;
  fnode, node : GListNode;
begin
  fnode := nil;
  hash := getHash(key);

  node := bucketList[hash].head;

  while (node <> nil) do
    begin
    if (GHashValue(node.element).key = key) then
      begin
      fnode := node;
      break;
      end;

    node := node.next;
    end;

  if (fnode <> nil) then
    bucketList[hash].remove(fnode);
end;

{
	Summary:
		Get size of hash table
}
function GHashTable.size() : integer;
var
   i : integer;
   total : integer;
begin
  total := 0;

  for i := 0 to hashsize - 1 do
    begin
    total := total + bucketList[i].size();
    end;

  Result := total;
end;

{
	Summary:
		Check if hash table is empty
}
function GHashTable.isEmpty() : boolean;
begin
  Result := size() = 0;
end;

{
	Summary:
		Display hash table statistics
}
procedure GHashTable.hashStats();
var
   i : integer;
   total : integer;
   load : single;
   min, max : integer;
begin
  total := 0;
  min := 65536;
  max := 0;

  for i := 0 to hashsize - 1 do
    begin
    total := total + bucketList[i].size();

    if (bucketList[i].size() < min) then
      min := bucketList[i].size();
    if (bucketList[i].size() > max) then
      max := bucketList[i].size();
    end;

  load := total / hashsize;

  writeln('Hash size ' + inttostr(hashsize) + ' with key ' + inttostr(hashprime));
  writeln('Total hash items : ' + inttostr(total));
  writeln('Load factor : ' + floattostrf(load, ffFixed, 7, 4));
end;

{
	Summary:
		Remove all items from hash table (See GDLinkedList.clear())
}
procedure GHashTable.clear();
var
   i : integer;
begin
  for i := 0 to hashsize - 1 do
    begin
    bucketList[i].ownsObjects := ownsObjects;
    bucketList[i].clear();
    end;
end;

{
	Summary:
		GHashTable constructor
}
constructor GHashTable.Create(size : integer);
var
   n : integer;
   primes : GPrimes;
begin
  inherited Create();

  primes := findPrimes(size + 32);

  randomize;
  hashsize := primes[length(primes) - 1];
  hashprime := primes[random(length(primes))];

  setlength(bucketList, hashsize);

  for n := 0 to hashsize - 1 do
    bucketList[n] := GDLinkedList.Create;

  hashFunc := defaultHash;

	_owns := true;
end;

{
	Summary:
		GHashTable destructor
}
destructor GHashTable.Destroy();
var
	n : integer;
begin
	clear();
	
  for n := 0 to hashsize - 1 do
    bucketList[n].Free;

  setlength(bucketList, 0);

  inherited Destroy();
end;

{
	Summary:
		Get iterator for the hash table
}		
function GHashTable.iterator() : GIterator;
begin
  Result := GHashTableIterator.Create(Self);
end;


{
	Summary:
		Add string to global string hash table
}
function hash_string(const src : string) : PString;
var
  hv : GHashValue;
  g : GString;
begin
  hv := str_hash._get(src);

  if (hv <> nil) then
    begin
    Result := @GString(hv.value).value;
    hv.addRef();
    end
  else
    begin
    g := GString.Create(src);

    str_hash.put(src, g);

    Result := @g.value;
    end;
end;

{
	Summary:
		Add string to global string hash table
}
function hash_string(src : PString) : PString;
var
  hv : GHashValue;
  g : GString;
begin
  hv := str_hash._get(src^);

  if (hv <> nil) then
    begin
    Result := @GString(hv.value).value;
    hv.addRef();
    end
  else
    begin
    g := GString.Create(src^);

    str_hash.put(src^, g);

    Result := @g.value;
    end;
end;

{
	Summary:
		Remove string from global string hash table
}
procedure unhash_string(var src : PString);
var
  hv : GHashValue;
begin
  if (src = nil) then
    exit;

  hv := str_hash._get(src^);

  if (hv <> nil) then
    begin
    hv.release();

    if (hv.refcount <= 0) then
      begin
      str_hash.remove(src^);
      hv.value.Free();
      hv.Free();
      end;
    end;

  src := nil;
end;

{ 
	Summary:
		GSingletonManager constructor
}
constructor GSingletonManager.Create();
begin
	inherited Create();
	
	infoList := TList.Create();
end;

{ 
	Summary:
		GSingletonManager destructor
}
destructor GSingletonManager.Destroy();
var
	x : integer;
begin
	if (infoList.Count > 0) then
		begin
		for x := 0 to infoList.Count - 1 do
			GSingletonInfo(infoList[x]).Free();
		end;
		
	FreeAndNil(infoList);
	
	inherited Destroy();
end;

{ 
	Summary:
		Adds instance to manager
}
procedure GSingletonManager.addInstance(instance : TObject);
var
	info : GSingletonInfo;
begin
	info := GSingletonInfo.Create();
	
	info.instance := instance;
	info.instanceType := instance.ClassType;
	info.refcount := 1;

	infoList.add(info);
end;

{
	Summary:
		Finds instance of classtype, or nil if unsuccessful
}
function GSingletonManager.findInstance(classType : TClass) : TObject;
var
	index : integer;
	info : GSingletonInfo;
begin
	Result := nil;

	for index := 0 to infoList.Count - 1 do
		begin
		info := GSingletonInfo(infoList[index]);
		
		if (info.instanceType = classType) then
			begin
			Result := info.instance;
			info.refcount := info.refcount + 1;
			exit;
			end;
		end;
end;

{
	Summary:
		Lowers refcount of classtype, removes if 0
}
function GSingletonManager.removeInstance(classType : TClass) : boolean;
var
	index : integer;
	info : GSingletonInfo;
begin
	Result := false;

	for index := 0 to infoList.Count - 1 do
		begin
		info := GSingletonInfo(infoList[index]);
		
		if (info.instanceType = classType) and (info.refcount > 0) then
			begin
			info.refcount := info.refcount - 1;
			
			if (info.refcount = 0) then
				Result := true;

			exit;
			end;
		end;
end;

{
	Summary:
		Returns (if it exists) a previous instance or a new instance
}
class function GSingleton.NewInstance : TObject;
begin
	Result := singletonManager.findInstance(Self);
	
	if (not Assigned(Result)) then
		begin
		Result := inherited NewInstance;
		GSingleton(Result).actualCreate();
		singletonManager.addInstance(Result);
		end;
end;

{
	Summary:
		Frees the instance
}
procedure GSingleton.FreeInstance;
begin
	if (singletonManager.removeInstance(Self.ClassType)) then
		begin
		GSingleton(Self).actualDestroy();

		inherited FreeInstance;
		end;	
end;

{
	Summary:
		Default GSingleton constructor 
}
constructor GSingleton.actualCreate();
begin
end;

{
	Summary:
		Default GSingleton destructor 
}
destructor GSingleton.actualDestroy();
begin
end;


initialization
	str_hash := GHashTable.Create(STR_HASH_SIZE);
	singletonManager := GSingletonManager.Create();

finalization
	FreeAndNil(singletonManager);
	FreeAndNil(str_hash);

end.