gvector.pp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit gvector;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. interface
  15. type
  16. { TVector }
  17. generic TVector<T> = class
  18. public
  19. type
  20. PT = ^ T;
  21. protected
  22. type
  23. TArr = array of T;
  24. private
  25. var
  26. FCapacity:SizeUInt;
  27. FDataSize:SizeUInt;
  28. FData:TArr;
  29. procedure SetValue(Position: SizeUInt; const Value: T); inline;
  30. function GetValue(Position: SizeUInt): T; inline;
  31. function GetMutable(Position: SizeUInt): PT; inline;
  32. function NewCapacity: SizeUInt;
  33. procedure IncreaseCapacity;
  34. const
  35. // todo: move these constants to implementation when
  36. // mantis #0021310 will be fixed.
  37. SVectorPositionOutOfRange = 'Vector position out of range';
  38. SAccessingElementOfEmptyVector = 'Accessing element of empty vector';
  39. type
  40. TVectorEnumerator = class
  41. private
  42. FVector: TVector;
  43. FPosition: SizeUInt;
  44. FFirstDone: Boolean;
  45. function GetCurrent: T; inline;
  46. public
  47. constructor Create(AVector: TVector);
  48. function GetEnumerator: TVectorEnumerator; inline;
  49. function MoveNext: Boolean; inline;
  50. property Current: T read GetCurrent;
  51. end;
  52. public
  53. constructor Create;
  54. function Size: SizeUInt; inline;
  55. procedure PushBack(const Value: T); inline;
  56. procedure PopBack; inline;
  57. function IsEmpty: boolean; inline;
  58. procedure Insert(Position: SizeUInt; const Value: T); inline;
  59. procedure Erase(Position: SizeUInt); inline;
  60. procedure Clear; inline;
  61. function Front: T; inline;
  62. function Back: T; inline;
  63. procedure Reserve(Num: SizeUInt);
  64. procedure Resize(Num: SizeUInt);
  65. function GetEnumerator: TVectorEnumerator; inline;
  66. property Items[i : SizeUInt]: T read getValue write setValue; default;
  67. property Mutable[i : SizeUInt]: PT read getMutable;
  68. end;
  69. implementation
  70. { TVector.TVectorEnumerator }
  71. constructor TVector.TVectorEnumerator.Create(AVector: TVector);
  72. begin
  73. FVector := AVector;
  74. end;
  75. function TVector.TVectorEnumerator.GetEnumerator: TVectorEnumerator;
  76. begin
  77. result:=self;
  78. end;
  79. function TVector.TVectorEnumerator.GetCurrent: T;
  80. begin
  81. Result := FVector[FPosition];
  82. end;
  83. function TVector.TVectorEnumerator.MoveNext: Boolean;
  84. begin
  85. if not FFirstDone then begin
  86. Result := FVector.Size > 0;
  87. FFirstDone := True;
  88. end else begin
  89. Result := FPosition < FVector.Size - 1;
  90. if Result then
  91. inc(FPosition);
  92. end;
  93. end;
  94. { TVector }
  95. constructor TVector.Create();
  96. begin
  97. FCapacity:=0;
  98. FDataSize:=0;
  99. end;
  100. procedure TVector.SetValue(Position: SizeUInt; const Value: T);
  101. begin
  102. Assert(position < size, SVectorPositionOutOfRange);
  103. FData[Position]:=Value;
  104. end;
  105. function TVector.GetValue(Position: SizeUInt): T;
  106. begin
  107. Assert(position < size, SVectorPositionOutOfRange);
  108. GetValue:=FData[Position];
  109. end;
  110. function TVector.GetMutable(Position: SizeUInt): PT;
  111. begin
  112. Assert(position < size, SVectorPositionOutOfRange);
  113. GetMutable:=@FData[Position];
  114. end;
  115. function TVector.Front(): T;
  116. begin
  117. Assert(size > 0, SAccessingElementOfEmptyVector);
  118. Front:=FData[0];
  119. end;
  120. function TVector.Back(): T;
  121. begin
  122. Assert(size > 0, SAccessingElementOfEmptyVector);
  123. Back:=FData[FDataSize-1];
  124. end;
  125. function TVector.Size(): SizeUInt;
  126. begin
  127. Size:=FDataSize;
  128. end;
  129. function TVector.IsEmpty(): boolean;
  130. begin
  131. IsEmpty := (Size() = 0);
  132. end;
  133. procedure TVector.PushBack(const Value: T);
  134. begin
  135. if FDataSize=FCapacity then
  136. IncreaseCapacity;
  137. FData[FDataSize]:=Value;
  138. inc(FDataSize);
  139. end;
  140. function TVector.NewCapacity: SizeUInt;
  141. const
  142. // if size is small, multiply by 2;
  143. // if size bigger but <256M, inc by 1/8*size;
  144. // otherwise inc by 1/16*size
  145. cSizeSmall = 1*1024*1024;
  146. cSizeBig = 256*1024*1024;
  147. var
  148. DataSize:SizeUInt;
  149. begin
  150. DataSize:=FCapacity*SizeOf(T);
  151. if FCapacity=0 then
  152. Result:=4
  153. else
  154. if DataSize<cSizeSmall then
  155. Result:=FCapacity*2
  156. else
  157. if DataSize<cSizeBig then
  158. Result:=FCapacity+FCapacity div 8
  159. else
  160. Result:=FCapacity+FCapacity div 16;
  161. end;
  162. procedure TVector.IncreaseCapacity();
  163. begin
  164. FCapacity:=NewCapacity;
  165. SetLength(FData, FCapacity);
  166. end;
  167. function TVector.GetEnumerator: TVectorEnumerator;
  168. begin
  169. Result := TVectorEnumerator.Create(self);
  170. end;
  171. procedure TVector.PopBack();
  172. begin
  173. if FDataSize > 0 then
  174. begin
  175. dec(FDataSize);
  176. // if a managed type, decrease the popped element's reference count (see http://bugs.freepascal.org/view.php?id=23938#)
  177. FData[FDataSize] := Default(T);
  178. end;
  179. end;
  180. procedure TVector.Insert(Position: SizeUInt; const Value: T);
  181. var
  182. def: T;
  183. begin
  184. if Position <= Size then // allow appending a new element at end of vector (but not beyond)
  185. begin
  186. if FDataSize = FCapacity then
  187. IncreaseCapacity;
  188. if Position < FDataSize then
  189. System.Move (FData[Position], FData[Position+1], (FDataSize - Position) * SizeOf(T));
  190. // update inserted item
  191. def := Default(T);
  192. Move(def, FData[Position], SizeOf(T)); // this will clear FData[Position] without changing the reference count
  193. FData[Position] := Value;
  194. inc(FDataSize);
  195. end;
  196. end;
  197. procedure TVector.Erase(Position: SizeUInt);
  198. begin
  199. if Position < Size then
  200. begin
  201. dec(FDataSize);
  202. // ensure that the data we want to erase is released
  203. FData[Position] := Default(T);
  204. Move(FData[Position+1], FData[Position], (FDataSize - Position) * SizeOf(T));
  205. end;
  206. end;
  207. procedure TVector.Clear;
  208. begin
  209. FDataSize:=0;
  210. end;
  211. procedure TVector.Reserve(Num: SizeUInt);
  212. begin
  213. if(Num < FCapacity) then
  214. exit
  215. else if (Num <= NewCapacity) then
  216. IncreaseCapacity
  217. else begin
  218. SetLength(FData, Num);
  219. FCapacity:=Num;
  220. end;
  221. end;
  222. procedure TVector.Resize(Num: SizeUInt);
  223. begin
  224. Reserve(Num);
  225. FDataSize:=Num;
  226. end;
  227. end.