I'm trying to fix this issue (and a few others besides.)
Problem
//None of these compile
type
PAType<T> = ^AType<T>;
P<T> = ^T;
PAType = ^AType<T>
So I'm trying to roll my own using a record and operator overloading.
I'm writing the following code:
TCell<T> = record
private
FData: T;
procedure SetData(Value: T); inline;
function GetData: T; inline;
public
property data: T read GetData write SetData;
end;
//Type safe pointer to T, because it knows SizeOf(T).
P<T> = record //wrapper around pointer: ^TCell<T>;^H^H^H^H any <T> actually
private
FPointerToT: pointer;
public
class operator Implicit(a: pointer): P<T>; inline;
class operator Implicit(a: P<T>): pointer; inline;
class operator Implicit(Cell: TCell<T>): P<T>; inline;
class operator Implicit(p: P<T>): TCell<T>; inline;
class operator Add(a: P<T>; b: NativeUInt): P<T>; inline;
class operator NotEqual(a,b : P<T>): Boolean; inline;
class operator NotEqual(a: P<T>; b: pointer): Boolean; inline;
class operator Equal(a,b : P<T>): Boolean; inline;
class operator GreaterThan(a,b : P<T>): Boolean; inline;
class operator GreaterThanOrEqual(a,b : P<T>): Boolean; inline;
class operator LessThan(a,b : P<T>): Boolean; inline;
class operator LessThanOrEqual(a,b : P<T>): Boolean; inline;
class operator Inc(a: P<T>): P<T>; inline;
class operator Dec(a: P<T>): P<T>; inline;
class operator Explicit(a: P<T>): T; inline;
end;
I'm writing a hashtable. Because I'm trying out different options for hashing.
The hashtable should take a record with data, put the record in a Dynamic Array (the record itself, not a pointer) and return a pointer to that record.
This will allow the application to store data in a more or less sequential order (with a few gaps).. That's good for the cache.
I want to use generics because even though the hashtable only holds one type at any one time, there are different classes to be hashed in different hashtables.
By returning a pointer I prevent dual storage.
The unfinished structure above allows me to write code like so:
//FCells: array of T;
//FArrayEnd: pointer; //points to element FCells[max_elements+1] (i.e. access violation)
function THashTable<K, T>.NextItem(Item: P<T>): P<T>;
begin
Result:= Item + SizeOf(T); //pointer arithmetic
if Result >= FArrayEnd then Result:= @FCells[0]; //comparison and assignment
end;
function THashTable<K, T>.Lookup(const key: K): P<T>;
var
Index: NativeUInt;
ItemKey: K;
begin
if IsValid(key) then begin
// Check regular cells
Index:= First_Cell(FGetHashFromKey(key)); //FGet.. is a user supplied key generation proc.
while (true) do begin
ItemKey:= FGetKey(FCells[Index]);
if (IsEqual(ItemKey, key)) then exit(@FCells[Index]);
if (IsEmpty(ItemKey)) then exit(nil); //nil pointers denote no-hit
Index:= NextIndex(Index);
end;
end
else { if IsEmpty(key) then } begin
// Check zero cell
Result:= @FZeroCell;
end;
end;
Note that I do not need a Nullable<T> to signify a miss. I standard nil pointer works.
I don't have to do type casts and the pointer is aware if how big it is.
It even knows a little bit about what T is.
I know there's a lot of gotcha's with Generics, so:
Before I get in too deep.
Will this work (in principle) or is this approach just wishful thinking?
type PGeneric = ^T<<-- does not compile;type PSomething = ^TMyClass<T><<-- does not...type PMyRecord<T> = ^MyRecord<T>does not compile. You get the point. I would like to be able to pass pointers to a type T around, something smarter than just a general typeless pointer