You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
4.9 KiB

  1. unit uutlArrayContainer;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils,
  6. uutlCommon;
  7. type
  8. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. generic TutlArrayContainer<T> = class(TutlInterfaceNoRefCount)
  10. protected type
  11. PT = ^T;
  12. strict private
  13. fList: PT;
  14. fCapacity: Integer;
  15. fOwnsItems: Boolean;
  16. fCanShrink: Boolean;
  17. fCanExpand: Boolean;
  18. function GetIsEmpty: Boolean; inline;
  19. protected
  20. function GetCount: Integer; virtual; abstract;
  21. procedure SetCount (const aValue: Integer); virtual; abstract;
  22. function GetInternalItem (const aIndex: Integer): PT;
  23. procedure SetCapacity (const aValue: integer); virtual;
  24. procedure Release (var aItem: T; const aFreeItem: Boolean); virtual;
  25. procedure Shrink (const aExactFit: Boolean);
  26. procedure Expand;
  27. protected
  28. property Count: Integer read GetCount write SetCount;
  29. property IsEmpty: Boolean read GetIsEmpty;
  30. property Capacity: Integer read fCapacity write SetCapacity;
  31. property CanShrink: Boolean read fCanShrink write fCanShrink;
  32. property CanExpand: Boolean read fCanExpand write fCanExpand;
  33. property OwnsItems: Boolean read fOwnsItems write fOwnsItems;
  34. public
  35. constructor Create(const aOwnsItems: Boolean);
  36. destructor Destroy; override;
  37. end;
  38. implementation
  39. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  40. //TutlArrayContainer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  41. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  42. function TutlArrayContainer.GetIsEmpty: Boolean;
  43. begin
  44. result := (Count = 0);
  45. end;
  46. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  47. function TutlArrayContainer.GetInternalItem(const aIndex: Integer): PT;
  48. begin
  49. if (aIndex < 0) or (aIndex >= fCapacity) then
  50. raise EOutOfRangeException.Create('capacity out of range', aIndex, 0, fCapacity-1);
  51. result := fList + aIndex;
  52. end;
  53. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  54. procedure TutlArrayContainer.SetCapacity(const aValue: integer);
  55. begin
  56. if (fCapacity = aValue) then
  57. exit;
  58. if (aValue < Count) then
  59. raise EArgumentException.Create('can not reduce capacity below count');
  60. ReAllocMem(fList, aValue * SizeOf(T));
  61. FillByte((fList + fCapacity)^, (aValue - fCapacity) * SizeOf(T), 0);
  62. fCapacity := aValue;
  63. end;
  64. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  65. procedure TutlArrayContainer.Release(var aItem: T; const aFreeItem: Boolean);
  66. begin
  67. utlFinalizeObject(aItem, TypeInfo(aItem), fOwnsItems and aFreeItem);
  68. FillByte(aItem, SizeOf(aItem), 0);
  69. end;
  70. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  71. procedure TutlArrayContainer.Shrink(const aExactFit: Boolean);
  72. begin
  73. if not fCanShrink then
  74. raise EInvalidOperation.Create('shrinking is not allowed');
  75. if (aExactFit) then
  76. SetCapacity(Count)
  77. else if (fCapacity > 128) and (Count < fCapacity shr 2) then // less than 25% used
  78. SetCapacity(fCapacity shr 1); // shrink to 50%
  79. end;
  80. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  81. procedure TutlArrayContainer.Expand;
  82. begin
  83. if (Count < fCapacity) then
  84. exit;
  85. if not fCanExpand then
  86. raise EInvalidOperation.Create('expanding is not allowed');
  87. if (fCapacity <= 0) then
  88. SetCapacity(4)
  89. else if (fCapacity < 128) then
  90. SetCapacity(fCapacity shl 1) // + 100%
  91. else
  92. SetCapacity(fCapacity + fCapacity shr 2); // + 25%
  93. end;
  94. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  95. constructor TutlArrayContainer.Create(const aOwnsItems: Boolean);
  96. begin
  97. inherited Create;
  98. fOwnsItems := aOwnsItems;
  99. fList := nil;
  100. fCapacity := 0;
  101. fCanExpand := true;
  102. fCanShrink := true;
  103. end;
  104. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  105. destructor TutlArrayContainer.Destroy;
  106. begin
  107. if Assigned(fList) then begin
  108. FreeMem(fList);
  109. fList := nil;
  110. end;
  111. inherited Destroy;
  112. end;
  113. end.