0

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?

6
  • I cannot discern a question here. What is your actual problem? What made you say "Not having pointers to Generic Types sucks." Commented Oct 8, 2013 at 3:56
  • Not to worry I'll self-answer as soon as I've got a minimal working solution. Commented Oct 8, 2013 at 4:04
  • Don't do that without fixing the question. I am genuinely interested. Please do tell us what limitation you have found. Commented Oct 8, 2013 at 4:04
  • 1
    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 Commented Oct 8, 2013 at 4:06
  • 1
    In short it is an attempt to fix the fact that Delphi does not allow me to declare a pointer to a Generic type, -class or -record. Commented Oct 8, 2013 at 4:26

1 Answer 1

3

You can have pointers to generic types. Like this:

type
  THashTable<K, T> = class
  public type
    TCell = TCell<T>;
    PCell = ^TCell;
  public
    function NextItem(Item: PCell): PCell;
  end;

To implement the pointer arithmetic you'll need this code:

function THashTable<K, T>.NextItem(Item: PCell): PCell;
begin
  Result := Item;
  inc(Result);
end;
Sign up to request clarification or add additional context in comments.

10 Comments

I know that trick, but try and declare the pointer on its own outside of the class and it will not work. I need to be able to use the pointer type in another class/unit.
When you've worked out the requirements, put them in the question please. Anyway, you can use that type outside the type. It is THashTable<K, T>.PCell.
Wait a minute, are types TCell and PCell accessible everywhere? Yes, they are, that's cool.
Ehmm does that also work for a record? I need it for a record. TCell<T> = record ..... PCell = ^TCell
I see no reason why it won't work for a record. All your requirements are spilling out in comments! ;-)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.