unit uutlListBase; {$mode objfpc}{$H+} interface uses Classes, SysUtils, uutlArrayContainer, uutlInterfaces, uutlEnumerator; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// generic TutlListBase = class( specialize TutlArrayContainer , specialize IEnumerable , specialize IutlEnumerable) public type IEnumerator = specialize IEnumerator; IutlEnumerator = specialize IutlEnumerator; private type TEnumerator = class( specialize TutlMemoryEnumerator , IEnumerator , IutlEnumerator) private fOwner: TutlListBase; protected { IEnumerator } procedure InternalReset; override; {$IFDEF UTL_ENUMERATORS} public { IutlEnumerator } function Reverse: IutlEnumerator; override; {$ENDIF} public constructor Create(const aOwner: TutlListBase; const aReversed: Boolean); reintroduce; end; strict private fCount: Integer; protected function GetCount: Integer; override; procedure SetCount(const aValue: Integer); override; function GetItem (const aIndex: Integer): T; virtual; procedure SetItem (const aIndex: Integer; aValue: T); virtual; procedure InsertIntern(const aIndex: Integer; constref aValue: T); virtual; procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean); virtual; public { IEnumerable } function GetEnumerator: IEnumerator; public { IutlEnumerable } function GetUtlEnumerator: IutlEnumerator; public property Count; property IsEmpty; property Capacity; property CanShrink; property CanExpand; property OwnsItems; procedure Clear; virtual; procedure ShrinkToFit; constructor Create(const aOwnsItems: Boolean); destructor Destroy; override; end; implementation uses uutlCommon; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlListBase.TEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListBase.TEnumerator.InternalReset; begin First := 0; Last := fOwner.Count-1; if (Last >= First) then Memory := fOwner.GetInternalItem(0) else Memory := nil; inherited InternalReset; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {$IFDEF UTL_ENUMERATORS} function TutlListBase.TEnumerator.Reverse: IutlEnumerator; begin result := TEnumerator.Create(fOwner, not Reversed); end; {$ENDIF} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlListBase.TEnumerator.Create(const aOwner: TutlListBase; const aReversed: Boolean); begin if not Assigned(aOwner) then raise EArgumentNilException.Create('aOwner'); fOwner := aOwner; inherited Create(nil, aReversed, 0, -1); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlListBase////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlListBase.GetCount: Integer; begin result := fCount; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListBase.SetCount(const aValue: Integer); begin if (aValue < Capacity) then Capacity := aValue; fCount := aValue; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlListBase.GetItem(const aIndex: Integer): T; begin if (aIndex < 0) or (aIndex >= Count) then raise EOutOfRangeException.Create(aIndex, 0, Count-1); result := GetInternalItem(aIndex)^; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListBase.SetItem(const aIndex: Integer; aValue: T); var p: PT; begin if (aIndex < 0) or (aIndex >= Count) then raise EOutOfRangeException.Create(aIndex, 0, Count-1); p := GetInternalItem(aIndex); Release(p^, true); p^ := aValue; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListBase.InsertIntern(const aIndex: Integer; constref aValue: T); var p: PT; begin if (aIndex < 0) or (aIndex > fCount) then raise EOutOfRangeException.Create(aIndex, 0, fCount); if (fCount = Capacity) then Expand; p := GetInternalItem(aIndex); if (aIndex < fCount) then System.Move(p^, (p+1)^, (fCount - aIndex) * SizeOf(T)); p^ := aValue; inc(fCount); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListBase.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean); var p: PT; begin if (aIndex < 0) or (aIndex >= fCount) then raise EOutOfRangeException.Create(aIndex, 0, fCount-1); dec(fCount); p := GetInternalItem(aIndex); Release(p^, aFreeItem); System.Move((p+1)^, p^, SizeOf(T) * (fCount - aIndex)); if CanShrink and (Capacity > 128) and (fCount < Capacity shr 2) then // only 25% used SetCapacity(Capacity shr 1); // set to 50% Capacity FillByte(GetInternalItem(fCount)^, (Capacity-fCount) * SizeOf(T), 0); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlListBase.GetEnumerator: IEnumerator; begin result := TEnumerator.Create(self, false); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlListBase.GetUtlEnumerator: specialize IutlEnumerator; begin result := TEnumerator.Create(self, false); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListBase.Clear; begin while (Count > 0) do begin dec(fCount); Release(GetInternalItem(fCount)^, true); end; fCount := 0; if CanShrink then ShrinkToFit; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListBase.ShrinkToFit; begin Shrink(true); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlListBase.Create(const aOwnsItems: Boolean); begin inherited Create(aOwnsItems); fCount := 0; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TutlListBase.Destroy; begin Clear; inherited Destroy; end; end.