gvector.pp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. {
  2. This file is part of the Free Pascal FCL library.
  3. BSD parts (c) 2011 Vlado Boza
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY;without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$mode objfpc}
  11. unit gvector;
  12. interface
  13. type
  14. { TVector }
  15. generic TVector<T> = class
  16. private
  17. type
  18. PT = ^ T;
  19. TArr = array of T;
  20. var
  21. FCapacity:SizeUInt;
  22. FDataSize:SizeUInt;
  23. FData:TArr;
  24. procedure SetValue(Position: SizeUInt; const Value: T); inline;
  25. function GetValue(Position: SizeUInt): T; inline;
  26. function GetMutable(Position: SizeUInt): PT; inline;
  27. procedure IncreaseCapacity; inline;
  28. const
  29. // todo: move these constants to implementation when
  30. // mantis #0021310 will be fixed.
  31. SVectorPositionOutOfRange = 'Vector position out of range';
  32. SAccessingElementOfEmptyVector = 'Accessing element of empty vector';
  33. type
  34. TVectorEnumerator = class
  35. private
  36. FVector: TVector;
  37. FPosition: SizeUInt;
  38. FFirstDone: Boolean;
  39. function GetCurrent: T; inline;
  40. public
  41. constructor Create(AVector: TVector);
  42. function MoveNext: Boolean; inline;
  43. property Current: T read GetCurrent;
  44. end;
  45. public
  46. constructor Create;
  47. function Size: SizeUInt; inline;
  48. procedure PushBack(const Value: T); inline;
  49. procedure PopBack; inline;
  50. function IsEmpty: boolean; inline;
  51. procedure Insert(Position: SizeUInt; const Value: T); inline;
  52. procedure Erase(Position: SizeUInt); inline;
  53. procedure Clear; inline;
  54. function Front: T; inline;
  55. function Back: T; inline;
  56. procedure Reserve(Num: SizeUInt);
  57. procedure Resize(Num: SizeUInt);
  58. function GetEnumerator: TVectorEnumerator; inline;
  59. property Items[i : SizeUInt]: T read getValue write setValue; default;
  60. property Mutable[i : SizeUInt]: PT read getMutable;
  61. end;
  62. implementation
  63. { TVector.TVectorEnumerator }
  64. constructor TVector.TVectorEnumerator.Create(AVector: TVector);
  65. begin
  66. FVector := AVector;
  67. end;
  68. function TVector.TVectorEnumerator.GetCurrent: T;
  69. begin
  70. Result := FVector[FPosition];
  71. end;
  72. function TVector.TVectorEnumerator.MoveNext: Boolean;
  73. begin
  74. if not FFirstDone then begin
  75. Result := FVector.Size > 0;
  76. FFirstDone := True;
  77. end else begin
  78. Result := FPosition < FVector.Size - 1;
  79. if Result then
  80. inc(FPosition);
  81. end;
  82. end;
  83. { TVector }
  84. constructor TVector.Create();
  85. begin
  86. FCapacity:=0;
  87. FDataSize:=0;
  88. end;
  89. procedure TVector.SetValue(Position: SizeUInt; const Value: T);
  90. begin
  91. Assert(position < size, SVectorPositionOutOfRange);
  92. FData[Position]:=Value;
  93. end;
  94. function TVector.GetValue(Position: SizeUInt): T;
  95. begin
  96. Assert(position < size, SVectorPositionOutOfRange);
  97. GetValue:=FData[Position];
  98. end;
  99. function TVector.GetMutable(Position: SizeUInt): PT;
  100. begin
  101. Assert(position < size, SVectorPositionOutOfRange);
  102. GetMutable:=@FData[Position];
  103. end;
  104. function TVector.Front(): T;
  105. begin
  106. Assert(size > 0, SAccessingElementOfEmptyVector);
  107. Front:=FData[0];
  108. end;
  109. function TVector.Back(): T;
  110. begin
  111. Assert(size > 0, SAccessingElementOfEmptyVector);
  112. Back:=FData[FDataSize-1];
  113. end;
  114. function TVector.Size(): SizeUInt;
  115. begin
  116. Size:=FDataSize;
  117. end;
  118. function TVector.IsEmpty(): boolean;
  119. begin
  120. IsEmpty := (Size() = 0);
  121. end;
  122. procedure TVector.PushBack(const Value: T);
  123. begin
  124. if FDataSize=FCapacity then
  125. IncreaseCapacity;
  126. FData[FDataSize]:=Value;
  127. inc(FDataSize);
  128. end;
  129. procedure TVector.IncreaseCapacity();
  130. begin
  131. if FCapacity=0 then
  132. FCapacity:=1
  133. else
  134. FCapacity:=FCapacity*2;
  135. SetLength(FData, FCapacity);
  136. end;
  137. function TVector.GetEnumerator: TVectorEnumerator;
  138. begin
  139. Result := TVectorEnumerator.Create(self);
  140. end;
  141. procedure TVector.PopBack();
  142. begin
  143. if FDataSize > 0 then
  144. begin
  145. dec(FDataSize);
  146. // if a managed type, decrease the popped element's reference count (see http://bugs.freepascal.org/view.php?id=23938#)
  147. FData[FDataSize] := Default(T);
  148. end;
  149. end;
  150. procedure TVector.Insert(Position: SizeUInt; const Value: T);
  151. var
  152. def: T;
  153. begin
  154. if Position <= Size then // allow appending a new element at end of vector (but not beyond)
  155. begin
  156. if FDataSize = FCapacity then
  157. IncreaseCapacity;
  158. if Position < FDataSize then
  159. System.Move (FData[Position], FData[Position+1], (FDataSize - Position) * SizeOf(T));
  160. // update inserted item
  161. def := Default(T);
  162. Move(def, FData[Position], SizeOf(T)); // this will clear FData[Position] without changing the reference count
  163. FData[Position] := Value;
  164. inc(FDataSize);
  165. end;
  166. end;
  167. procedure TVector.Erase(Position: SizeUInt);
  168. begin
  169. if Position < Size then
  170. begin
  171. dec(FDataSize);
  172. // ensure that the data we want to erase is released
  173. FData[Position] := Default(T);
  174. Move(FData[Position+1], FData[Position], (FDataSize - Position) * SizeOf(T));
  175. end;
  176. end;
  177. procedure TVector.Clear;
  178. begin
  179. FDataSize:=0;
  180. end;
  181. procedure TVector.Reserve(Num: SizeUInt);
  182. begin
  183. if(Num < FCapacity) then
  184. exit
  185. else if(Num <= 2*FCapacity) then
  186. IncreaseCapacity
  187. else begin
  188. SetLength(FData, Num);
  189. FCapacity:=Num;
  190. end;
  191. end;
  192. procedure TVector.Resize(Num: SizeUInt);
  193. begin
  194. Reserve(Num);
  195. FDataSize:=Num;
  196. end;
  197. end.