gvector.pp 6.0 KB

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