2
0
mirror of https://github.com/dpethes/rerogue.git synced 2025-06-07 18:58:32 +02:00
rerogue/hob_display/genericstructlist.pas
2014-10-26 17:40:21 +01:00

225 lines
6.6 KiB
ObjectPascal

{
Based on FPC FGL unit, copyright by FPC team.
License of FPC RTL is the same as our engine (modified LGPL,
see COPYING.txt for details).
Fixed to compile also under FPC 2.4.0 and 2.2.4.
Some small comfortable methods added.
}
{ Generic list of any type (TGenericStructList). }
unit GenericStructList;
{$mode objfpc}{$H+}
{$IF defined(VER2_2)} {$DEFINE OldSyntax} {$IFEND}
{$IF defined(VER2_4)} {$DEFINE OldSyntax} {$IFEND}
{$define HAS_ENUMERATOR}
{$ifdef VER2_2} {$undef HAS_ENUMERATOR} {$endif}
{$ifdef VER2_4_0} {$undef HAS_ENUMERATOR} {$endif}
{ Just undef enumerator always, in FPC 2.7.1 it's either broken
or I shouldn't overuse TFPGListEnumeratorSpec. }
{$undef HAS_ENUMERATOR}
{ FPC < 2.6.0 had buggy version of the Extract function,
also with different interface, see http://bugs.freepascal.org/view.php?id=19960. }
{$define HAS_EXTRACT}
{$ifdef VER2_2} {$undef HAS_EXTRACT} {$endif}
{$ifdef VER2_4} {$undef HAS_EXTRACT} {$endif}
interface
uses FGL;
type
{ Generic list of types that are compared by CompareByte.
This is equivalent to TFPGList, except it doesn't override IndexOf,
so your type doesn't need to have a "=" operator built-in inside FPC.
When calling IndexOf or Remove, it will simply compare values using
CompareByte, this is what TFPSList.IndexOf uses.
This way it works to create lists of records, vectors (constant size arrays),
old-style TP objects, and also is suitable to create a list of methods
(since for methods, the "=" is broken, for Delphi compatibility,
see http://bugs.freepascal.org/view.php?id=9228).
We also add some trivial helper methods like @link(Add) and @link(L). }
{ TGenericStructList }
generic TGenericStructList<T> = class(TFPSList)
private
type
TCompareFunc = function(const Item1, Item2: T): Integer;
TTypeList = array[0..MaxGListSize] of T;
PTypeList = ^TTypeList;
PT = ^T;
{$ifdef HAS_ENUMERATOR} TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>; {$endif}
{$ifndef OldSyntax}protected var{$else}
{$ifdef PASDOC}protected var{$else} { PasDoc can't handle "var protected", and I don't know how/if they should be handled? }
var protected{$endif}{$endif}
FOnCompare: TCompareFunc;
procedure CopyItem(Src, Dest: Pointer); override;
procedure Deref(Item: Pointer); override;
function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
function ItemPtrCompare(Item1, Item2: Pointer): Integer;
procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
public
constructor Create;
function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
{$ifdef HAS_EXTRACT} function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif} {$endif}
function First: T; {$ifdef CLASSESINLINE} inline; {$endif}
{$ifdef HAS_ENUMERATOR} function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef CLASSESINLINE} inline; {$endif} {$endif}
function IndexOf(const Item: T): Integer;
procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
{$ifndef OldSyntax}
procedure Assign(Source: TGenericStructList);
{$endif OldSyntax}
function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
procedure Sort(Compare: TCompareFunc);
property Items[Index: Integer]: T read Get write Put; default;
property List: PTypeList read GetList;
{ Pointer to items. Exactly like @link(List), but this points to a single item,
which means you can access particular item by @code(L[I]) instead of
@code(List^[I]) in FPC objfpc mode.
This is just trivial shortcut, but we use direct access a @italic(lot)
for structures. Reasonis: using Items[] default
property means copying the structures, which is
@orderedList(
@item(very dangerous (you can trivially easy modify a temporary result))
@item(slow (important for us, since these are used for vector arrays that
are crucial for renderer and various processing).)
) }
function L: PT;
{ Increase Count and return pointer to new item.
Comfortable and efficient way to add a new item that you want to immediately
initialize. }
function Add: PT;
function Copy: TGenericStructList;
end;
implementation
constructor TGenericStructList.Create;
begin
inherited Create(sizeof(T));
end;
procedure TGenericStructList.CopyItem(Src, Dest: Pointer);
begin
T(Dest^) := T(Src^);
end;
procedure TGenericStructList.Deref(Item: Pointer);
begin
Finalize(T(Item^));
end;
function TGenericStructList.Get(Index: Integer): T;
begin
Result := T(inherited Get(Index)^);
end;
function TGenericStructList.GetList: PTypeList;
begin
Result := PTypeList(FList);
end;
function TGenericStructList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
begin
Result := FOnCompare(T(Item1^), T(Item2^));
end;
procedure TGenericStructList.Put(Index: Integer; const Item: T);
begin
inherited Put(Index, @Item);
end;
function TGenericStructList.Add(const Item: T): Integer;
begin
Result := inherited Add(@Item);
end;
{$ifdef HAS_EXTRACT}
function TGenericStructList.Extract(const Item: T): T;
begin
inherited Extract(@Item, @Result);
end;
{$endif}
function TGenericStructList.First: T;
begin
Result := T(inherited First^);
end;
{$ifdef HAS_ENUMERATOR}
function TGenericStructList.GetEnumerator: TFPGListEnumeratorSpec;
begin
Result := TFPGListEnumeratorSpec.Create(Self);
end;
{$endif}
function TGenericStructList.IndexOf(const Item: T): Integer;
begin
Result := inherited IndexOf(@Item);
end;
procedure TGenericStructList.Insert(Index: Integer; const Item: T);
begin
T(inherited Insert(Index)^) := Item;
end;
function TGenericStructList.Last: T;
begin
Result := T(inherited Last^);
end;
{$ifndef OldSyntax}
procedure TGenericStructList.Assign(Source: TGenericStructList);
var
i: Integer;
begin
Clear;
for I := 0 to Source.Count - 1 do
Add(Source[i]);
end;
{$endif OldSyntax}
function TGenericStructList.Remove(const Item: T): Integer;
begin
Result := IndexOf(Item);
if Result >= 0 then
Delete(Result);
end;
procedure TGenericStructList.Sort(Compare: TCompareFunc);
begin
FOnCompare := Compare;
inherited Sort(@ItemPtrCompare);
end;
function TGenericStructList.L: PT;
begin
Result := PT(FList);
end;
function TGenericStructList.Add: PT;
begin
Count := Count + 1;
Result := Addr(L[Count - 1]);
end;
function TGenericStructList.Copy: TGenericStructList;
begin
result := TGenericStructList.Create;
result.Assign(Self);
end;
end.