Quick.Collections.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. { ***************************************************************************
  2. Copyright (c) 2016-2020 Kike Pérez
  3. Unit : Quick.Collections
  4. Description : Generic Collections
  5. Author : Kike Pérez
  6. Version : 1.2
  7. Created : 07/03/2020
  8. Modified : 20/03/2020
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Collections;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. System.SysUtils,
  26. TypInfo,
  27. System.Types,
  28. System.Generics.Defaults,
  29. System.Generics.Collections,
  30. Quick.Linq;
  31. type
  32. IListBase<T> = interface
  33. ['{9A9B2DB9-14E4-49DD-A628-F84F50539F41}']
  34. function GetList: TArray<T>;
  35. function GetCapacity: Integer;
  36. procedure SetCapacity(Value: Integer); overload;
  37. function GetCount : Integer;
  38. procedure SetCount(Value: Integer);
  39. function GetItem(Index: Integer): T;
  40. procedure SetItem(Index: Integer; const Value: T);
  41. function GetEnumerator : TEnumerator<T>;
  42. function Add(const Value: T): Integer;
  43. procedure AddRange(const Values: array of T); overload;
  44. procedure AddRange(const Collection: IEnumerable<T>); overload;
  45. procedure AddRange(const Collection: TEnumerable<T>); overload;
  46. procedure Insert(Index: Integer; const Value: T);
  47. procedure InsertRange(Index: Integer; const Values: array of T; Count: Integer); overload;
  48. procedure InsertRange(Index: Integer; const Values: array of T); overload;
  49. procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
  50. procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;
  51. function Remove(const Value: T): Integer;
  52. function RemoveItem(const Value: T; Direction: TDirection): Integer;
  53. procedure Delete(Index: Integer);
  54. procedure DeleteRange(AIndex, ACount: Integer);
  55. function ExtractItem(const Value: T; Direction: TDirection): T;
  56. function Extract(const Value: T): T;
  57. function ExtractAt(Index: Integer): T;
  58. procedure Exchange(Index1, Index2: Integer);
  59. procedure Move(CurIndex, NewIndex: Integer);
  60. function First: T;
  61. function Last: T;
  62. procedure Clear;
  63. function Contains(const Value: T): Boolean;
  64. function IndexOf(const Value: T): Integer;
  65. function IndexOfItem(const Value: T; Direction: TDirection): Integer;
  66. function LastIndexOf(const Value: T): Integer;
  67. procedure Reverse;
  68. procedure Sort; overload;
  69. procedure Sort(const AComparer: IComparer<T>); overload;
  70. function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;
  71. function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;
  72. procedure TrimExcess;
  73. function ToArray: TArray<T>;
  74. procedure FromList(const aList : TList<T>);
  75. function ToList : TList<T>;
  76. property Capacity: Integer read GetCapacity write SetCapacity;
  77. property Count: Integer read GetCount write SetCount;
  78. property Items[Index: Integer]: T read GetItem write SetItem; default;
  79. property List: TArray<T> read GetList;
  80. function Any : Boolean; overload;
  81. end;
  82. IList<T> = interface(IListBase<T>)
  83. ['{78952BD5-7D15-42BB-ADCB-2F835DF879A0}']
  84. function Any(const aMatchString : string; aUseRegEx : Boolean) : Boolean; overload;
  85. function Where(const aMatchString : string; aUseRegEx : Boolean) : ILinqArray<T>; overload;
  86. function Where(const aWhereClause : string; aWhereValues : array of const) : ILinqQuery<T>; overload;
  87. function Where(const aWhereClause: string): ILinqQuery<T>; overload;
  88. {$IFNDEF FPC}
  89. function Where(aPredicate : TPredicate<T>) : ILinqQuery<T>; overload;
  90. {$ENDIF}
  91. end;
  92. IObjectList<T : class> = interface(IListBase<T>)
  93. ['{7380847B-9F94-4FB8-8B73-DC8ACAFF1729}']
  94. function Any(const aWhereClause : string; aValues : array of const) : Boolean; overload;
  95. function Where(const aWhereClause : string; aWhereValues : array of const) : ILinqQuery<T>; overload;
  96. function Where(const aWhereClause: string): ILinqQuery<T>; overload;
  97. function Where(aPredicate : TPredicate<T>): ILinqQuery<T>; overload;
  98. end;
  99. TXList<T> = class(TInterfacedObject,IList<T>)
  100. private type
  101. arrayofT = array of T;
  102. private
  103. fList : TList<T>;
  104. function GetList: TArray<T>;
  105. function GetCapacity: Integer;
  106. procedure SetCapacity(Value: Integer); overload;
  107. function GetCount : Integer;
  108. procedure SetCount(Value: Integer);
  109. function GetItem(Index: Integer): T;
  110. procedure SetItem(Index: Integer; const Value: T);
  111. function GetEnumerator : TEnumerator<T>;
  112. public
  113. constructor Create;
  114. destructor Destroy; override;
  115. function Add(const Value: T): Integer; inline;
  116. procedure AddRange(const Values: array of T); overload;
  117. procedure AddRange(const Collection: IEnumerable<T>); overload; inline;
  118. procedure AddRange(const Collection: TEnumerable<T>); overload;
  119. procedure Insert(Index: Integer; const Value: T); inline;
  120. procedure InsertRange(Index: Integer; const Values: array of T; Count: Integer); overload;
  121. procedure InsertRange(Index: Integer; const Values: array of T); overload;
  122. procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
  123. procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;
  124. function Remove(const Value: T): Integer; inline;
  125. function RemoveItem(const Value: T; Direction: TDirection): Integer; inline;
  126. procedure Delete(Index: Integer); inline;
  127. procedure DeleteRange(AIndex, ACount: Integer); inline;
  128. function ExtractItem(const Value: T; Direction: TDirection): T; inline;
  129. function Extract(const Value: T): T; inline;
  130. function ExtractAt(Index: Integer): T; inline;
  131. procedure Exchange(Index1, Index2: Integer); inline;
  132. procedure Move(CurIndex, NewIndex: Integer); inline;
  133. function First: T; inline;
  134. function Last: T; inline;
  135. procedure Clear; inline;
  136. function Contains(const Value: T): Boolean; inline;
  137. function IndexOf(const Value: T): Integer; inline;
  138. function IndexOfItem(const Value: T; Direction: TDirection): Integer; inline;
  139. function LastIndexOf(const Value: T): Integer; inline;
  140. procedure Reverse; inline;
  141. procedure Sort; overload; inline;
  142. procedure Sort(const AComparer: IComparer<T>); overload; inline;
  143. function BinarySearch(const Item: T; out Index: Integer): Boolean; overload; inline;
  144. function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload; inline;
  145. procedure TrimExcess; inline;
  146. function ToArray: TArray<T>; inline;
  147. property Capacity: Integer read GetCapacity write SetCapacity;
  148. property Count: Integer read GetCount write SetCount;
  149. property Items[Index: Integer]: T read GetItem write SetItem; default;
  150. property List: arrayofT read GetList;
  151. procedure FromList(const aList : TList<T>);
  152. function ToList : TList<T>;
  153. function Any : Boolean; overload; virtual;
  154. function Where(const aWhereClause : string; aWhereValues : array of const) : ILinqQuery<T>; overload;
  155. function Where(const aWhereClause: string): ILinqQuery<T>; overload;
  156. function Any(const aMatchString : string; aUseRegEx : Boolean) : Boolean; overload;
  157. function Where(const aMatchString : string; aUseRegEx : Boolean) : ILinqArray<T>; overload;
  158. {$IFNDEF FPC}
  159. function Where(aPredicate : TPredicate<T>) : ILinqQuery<T>; overload;
  160. {$ENDIF}
  161. end;
  162. TXObjectList<T : class> = class(TXList<T>,IObjectList<T>)
  163. private
  164. fOwnsObjects : Boolean;
  165. procedure InternalOnNotify(Sender: TObject; const Item: T; Action: TCollectionNotification);
  166. public
  167. constructor Create(aOwnedObjects : Boolean = True);
  168. destructor Destroy; override;
  169. function Any(const aWhereClause : string; aValues : array of const) : Boolean; overload;
  170. function Where(const aWhereClause : string; aWhereValues : array of const) : ILinqQuery<T>; overload;
  171. function Where(const aWhereClause: string): ILinqQuery<T>; overload;
  172. function Where(aPredicate : TPredicate<T>): ILinqQuery<T>; overload;
  173. end;
  174. ECollectionError = class(Exception);
  175. ECollectionNotSupported = class(Exception);
  176. implementation
  177. { TXList<T> }
  178. constructor TXList<T>.Create;
  179. begin
  180. fList := TList<T>.Create;
  181. end;
  182. destructor TXList<T>.Destroy;
  183. begin
  184. fList.Free;
  185. inherited;
  186. end;
  187. function TXList<T>.Add(const Value: T): Integer;
  188. begin
  189. Result := fList.Add(Value);
  190. end;
  191. procedure TXList<T>.AddRange(const Values: array of T);
  192. begin
  193. fList.AddRange(Values);
  194. end;
  195. procedure TXList<T>.AddRange(const Collection: IEnumerable<T>);
  196. begin
  197. fList.AddRange(Collection);
  198. end;
  199. procedure TXList<T>.AddRange(const Collection: TEnumerable<T>);
  200. begin
  201. fList.AddRange(Collection);
  202. end;
  203. function TXList<T>.Any(const aMatchString: string; aUseRegEx: Boolean): Boolean;
  204. begin
  205. Result := Where(aMatchString,aUseRegEx).Any;
  206. end;
  207. function TXList<T>.Any: Boolean;
  208. begin
  209. Result := fList.Count > 0;
  210. end;
  211. function TXList<T>.BinarySearch(const Item: T; out Index: Integer): Boolean;
  212. begin
  213. Result := fList.BinarySearch(Item,Index);
  214. end;
  215. function TXList<T>.BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean;
  216. begin
  217. Result := fList.BinarySearch(Item,Index,AComparer);
  218. end;
  219. procedure TXList<T>.Clear;
  220. begin
  221. fList.Clear;
  222. end;
  223. function TXList<T>.Contains(const Value: T): Boolean;
  224. begin
  225. Result := fList.Contains(Value);
  226. end;
  227. procedure TXList<T>.Delete(Index: Integer);
  228. begin
  229. fList.Delete(Index);
  230. end;
  231. procedure TXList<T>.DeleteRange(AIndex, ACount: Integer);
  232. begin
  233. fList.DeleteRange(aIndex,aCount);
  234. end;
  235. procedure TXList<T>.Exchange(Index1, Index2: Integer);
  236. begin
  237. fList.Exchange(Index1,Index2);
  238. end;
  239. function TXList<T>.Extract(const Value: T): T;
  240. begin
  241. Result := fList.Extract(Value);
  242. end;
  243. function TXList<T>.ExtractAt(Index: Integer): T;
  244. begin
  245. Result := fList.ExtractAt(Index);
  246. end;
  247. function TXList<T>.ExtractItem(const Value: T; Direction: TDirection): T;
  248. begin
  249. Result := fList.ExtractItem(Value,Direction);
  250. end;
  251. function TXList<T>.First: T;
  252. begin
  253. Result := fList.First;
  254. end;
  255. procedure TXList<T>.FromList(const aList: TList<T>);
  256. var
  257. value : T;
  258. begin
  259. for value in aList do fList.Add(value);
  260. end;
  261. function TXList<T>.GetCapacity: Integer;
  262. begin
  263. Result := fList.Capacity;
  264. end;
  265. function TXList<T>.GetCount: Integer;
  266. begin
  267. Result := fList.Count;
  268. end;
  269. function TXList<T>.GetEnumerator: TEnumerator<T>;
  270. begin
  271. Result := fList.GetEnumerator;
  272. end;
  273. function TXList<T>.GetItem(Index: Integer): T;
  274. begin
  275. Result := fList.Items[Index];
  276. end;
  277. function TXList<T>.GetList: TArray<T>;
  278. begin
  279. Result := fList.ToArray;
  280. end;
  281. function TXList<T>.IndexOf(const Value: T): Integer;
  282. begin
  283. Result := fList.IndexOf(Value);
  284. end;
  285. function TXList<T>.IndexOfItem(const Value: T; Direction: TDirection): Integer;
  286. begin
  287. Result := fList.IndexOfItem(Value,Direction);
  288. end;
  289. procedure TXList<T>.Insert(Index: Integer; const Value: T);
  290. begin
  291. fList.Insert(Index,Value);
  292. end;
  293. procedure TXList<T>.InsertRange(Index: Integer; const Collection: IEnumerable<T>);
  294. begin
  295. fList.InsertRange(Index,Collection);
  296. end;
  297. procedure TXList<T>.InsertRange(Index: Integer; const Collection: TEnumerable<T>);
  298. begin
  299. fList.InsertRange(index,Collection);
  300. end;
  301. procedure TXList<T>.InsertRange(Index: Integer; const Values: array of T; Count: Integer);
  302. begin
  303. fList.InsertRange(Index,Values,Count);
  304. end;
  305. procedure TXList<T>.InsertRange(Index: Integer; const Values: array of T);
  306. begin
  307. fList.InsertRange(index,Values);
  308. end;
  309. function TXList<T>.Last: T;
  310. begin
  311. Result := fList.Last;
  312. end;
  313. function TXList<T>.LastIndexOf(const Value: T): Integer;
  314. begin
  315. Result := fList.LastIndexOf(Value);
  316. end;
  317. procedure TXList<T>.Move(CurIndex, NewIndex: Integer);
  318. begin
  319. fList.Move(CurIndex,NewIndex);
  320. end;
  321. function TXList<T>.Remove(const Value: T): Integer;
  322. begin
  323. Result := fList.Remove(Value);
  324. end;
  325. function TXList<T>.RemoveItem(const Value: T; Direction: TDirection): Integer;
  326. begin
  327. Result := fList.RemoveItem(Value,Direction);
  328. end;
  329. procedure TXList<T>.Reverse;
  330. begin
  331. fList.Reverse;
  332. end;
  333. procedure TXList<T>.SetCapacity(Value: Integer);
  334. begin
  335. fList.Capacity := Value;
  336. end;
  337. procedure TXList<T>.SetCount(Value: Integer);
  338. begin
  339. fList.Count := Value;
  340. end;
  341. procedure TXList<T>.SetItem(Index: Integer; const Value: T);
  342. begin
  343. fList.Items[Index] := Value;
  344. end;
  345. procedure TXList<T>.Sort(const AComparer: IComparer<T>);
  346. begin
  347. fList.Sort(AComparer);
  348. end;
  349. procedure TXList<T>.Sort;
  350. begin
  351. fList.Sort;
  352. end;
  353. function TXList<T>.ToArray: TArray<T>;
  354. begin
  355. Result := fList.ToArray;
  356. end;
  357. function TXList<T>.ToList: TList<T>;
  358. var
  359. value : T;
  360. begin
  361. Result := TList<T>.Create;
  362. for value in fList do Result.Add(value);
  363. end;
  364. procedure TXList<T>.TrimExcess;
  365. begin
  366. fList.TrimExcess;
  367. end;
  368. function TXList<T>.Where(const aMatchString: string; aUseRegEx: Boolean): ILinqArray<T>;
  369. begin
  370. Result := TLinqArray<T>.Create(fList.ToArray);
  371. Result.Where(aMatchString, aUseRegEx);
  372. end;
  373. function TXList<T>.Where(const aWhereClause: string; aWhereValues: array of const): ILinqQuery<T>;
  374. begin
  375. if PTypeInfo(typeInfo(T)).Kind <> tkClass then raise ECollectionNotSupported.Create('TXList<T>.Where only supports classes. Use MatchString overload method instead!');
  376. Result := TLinqQuery<TObject>.Create(TObjectList<TObject>(Self.fList)).Where(aWhereClause,aWhereValues) as ILinqQuery<T>;
  377. end;
  378. function TXList<T>.Where(const aWhereClause: string): ILinqQuery<T>;
  379. begin
  380. if PTypeInfo(typeInfo(T)).Kind <> tkClass then raise ECollectionNotSupported.Create('TXList<T>.Where only supports classes. Use MatchString overload method instead!');
  381. Result := TLinqQuery<TObject>.Create(TObjectList<TObject>(Self.fList)).Where(aWhereClause) as ILinqQuery<T>;
  382. end;
  383. function TXList<T>.Where(aPredicate: TPredicate<T>): ILinqQuery<T>;
  384. begin
  385. if PTypeInfo(typeInfo(T)).Kind <> tkClass then raise ECollectionNotSupported.Create('TXList<T>.Where only supports classes. Use MatchString overload method instead!');
  386. Result := TLinqQuery<TObject>.Create(TObjectList<TObject>(Self.fList)).Where(TPredicate<TObject>(aPredicate)) as ILinqQuery<T>;
  387. end;
  388. { TXObjectList<T> }
  389. function TXObjectList<T>.Any(const aWhereClause: string; aValues: array of const): Boolean;
  390. var
  391. query : ILinqQuery<T>;
  392. begin
  393. query := TLinqQuery<T>.Create(Self.fList);
  394. Result := query.Where(aWhereClause,aValues).Count > 0;
  395. end;
  396. constructor TXObjectList<T>.Create(aOwnedObjects: Boolean);
  397. begin
  398. inherited Create;
  399. fOwnsObjects := aOwnedObjects;
  400. fList.OnNotify := InternalOnNotify;
  401. end;
  402. destructor TXObjectList<T>.Destroy;
  403. begin
  404. inherited;
  405. end;
  406. procedure TXObjectList<T>.InternalOnNotify(Sender: TObject; const Item: T; Action: TCollectionNotification);
  407. begin
  408. if (fOwnsObjects) and (Action = TCollectionNotification.cnRemoved) then
  409. begin
  410. if Assigned(Item) then Item.DisposeOf;
  411. //if PTypeInfo(typeInfo(T)).Kind = tkClass then
  412. //PObject(@Item).DisposeOf;
  413. end;
  414. end;
  415. function TXObjectList<T>.Where(const aWhereClause: string): ILinqQuery<T>;
  416. begin
  417. Result := TLinqQuery<T>.Create(Self.fList).Where(aWhereClause);
  418. end;
  419. function TXObjectList<T>.Where(const aWhereClause: string; aWhereValues: array of const): ILinqQuery<T>;
  420. begin
  421. Result := TLinqQuery<T>.Create(Self.fList).Where(aWhereClause,aWhereValues);
  422. end;
  423. function TXObjectList<T>.Where(aPredicate: TPredicate<T>): ILinqQuery<T>;
  424. begin
  425. Result := TLinqQuery<T>.Create(Self.fList).Where(aPredicate);
  426. end;
  427. end.