views:

63

answers:

1

I tried my hand at a generic class, and on a second attempt I've tried to make a generic locked pool. I almost got it to work I stumble on the spot where I want to put a generic typed class into a locked tlist obtained from tthreadlist.

The main question is:

  • Does anybody know a solution to this problem? (see "problem spot" in the source)

Hints, minor questions:

  • Do I need an additional constraint that signals reference? (I tried adding ,reference to the already existing class and constructor)
  • Does sb know a good overview page of all "special" generic constraints (class,constructor) . Couldn't find much in the manual.
  • the company is at D2009, but I've a single license DXE for migration preparation purposes.

The objects used by this pool are tobject, and worse, some of them have some crucial methods that must be inlined. (it is an image processing app, which is also why I'm not that concerned with relative simply locks. Granularity is coarse). I mention this, since it might make interface based solutions difficult.

type
     TLockedPool<T:class,constructor>   =   class
                                  private
                                    lst : tthreadlist;
                                  public
                                    type sometype =t;  // part of workarounds.
                                    destructor  destroy;
                                    constructor create;
                                    function    getitem:T;
                                    procedure   putitem(var b:T);
                                   end;

 constructor TLockedPool<T>.create;
 begin
  lst:=TThreadlist.Create;
 end;

destructor TLockedPool<T>.destroy;
var i : integer;
    v: tlist;
begin
  v:=lst.locklist;
  for i:=0 to v.count-1 do
    Tobject(v[i]).Free;
  lst.unlocklist;
  v.clear;
  freeandnil(lst);
 inherited;
end;

function TLockedPool<T>.getitem: T;
var cnt:integer;
   v : tlist;
begin
  v:=lst.LockList;
  cnt:=v.Count;
  if cnt>0 then
    begin
      result:=tobject(v[cnt-1]);
      v.delete(cnt-1);
    end
  else
    begin
     result:=T.create;
    end;
  lst.UnlockList;
end;

procedure TLockedPool<T>.putitem(var b: T);
var  v : Tlist;
 x : sometype;
begin
if assigned(b) then // some older parts of the framework are dirty and try to put in NILs.
    begin
      v:=lst.LockList;
      x:=b;
      v.Add(pointer(sometype(x)));  // <--- the problemspot
      lst.unlocklist;
    end;
 b:=nil;
end;
+2  A: 

Use v.Add(TObject(x)) or, if you must (it may not work in 2009, awkward for me to check), v.Add(PPointer(@x)^).

Barry Kelly
I had tried the first, but of course the second works. In 2009 too. Can this be considered a bug (worth QCing) ? Since afaik the class constraint clearly identifies it as a ref type. Ohh... and thanks obviously :-)
Marco van de Voort
The implicit conversion to Pointer from a value of a type parameter type constrained to class, perhaps. I think it may be a duplicate. On the other hand, I (personally) think the implicit casts between Pointer and object types to be undesirable: convenient but hacky. But it would probably not be me that looked at / tried to fix this bug.
Barry Kelly
I was more worried that the explicit tobject() typecasts either were rejected directly (above code) or failed at specialization time (the opposite case, casting the tlist element back to the generic type). I don't care about the implicit case.
Marco van de Voort
The explicit TObject casts are fixed in D2010 and up, I believe. Certainly they're fixed in my local dev tree :)
Barry Kelly