Quick.Collections.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  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 : 31/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. procedure FromArray(const aArray: TArray<T>);
  76. function ToList : TList<T>;
  77. property Capacity: Integer read GetCapacity write SetCapacity;
  78. property Count: Integer read GetCount write SetCount;
  79. property Items[Index: Integer]: T read GetItem write SetItem; default;
  80. property List: TArray<T> read GetList;
  81. function Any : Boolean; overload;
  82. end;
  83. IList<T> = interface(IListBase<T>)
  84. ['{78952BD5-7D15-42BB-ADCB-2F835DF879A0}']
  85. function Any(const aMatchString : string; aUseRegEx : Boolean) : Boolean; overload;
  86. function Where(const aMatchString : string; aUseRegEx : Boolean) : ILinqArray<T>; overload;
  87. function Where(const aWhereClause : string; aWhereValues : array of const) : ILinqQuery<T>; overload;
  88. function Where(const aWhereClause: string): ILinqQuery<T>; overload;
  89. {$IFNDEF FPC}
  90. function Where(aPredicate : TPredicate<T>) : ILinqQuery<T>; overload;
  91. {$ENDIF}
  92. end;
  93. IObjectList<T : class> = interface(IListBase<T>)
  94. ['{7380847B-9F94-4FB8-8B73-DC8ACAFF1729}']
  95. function Any(const aWhereClause : string; aValues : array of const) : Boolean; overload;
  96. function Where(const aWhereClause : string; aWhereValues : array of const) : ILinqQuery<T>; overload;
  97. function Where(const aWhereClause: string): ILinqQuery<T>; overload;
  98. function Where(aPredicate : TPredicate<T>): ILinqQuery<T>; overload;
  99. end;
  100. TxList<T> = class(TInterfacedObject,IList<T>)
  101. private type
  102. arrayofT = array of T;
  103. private
  104. fList : TList<T>;
  105. function GetList: TArray<T>;
  106. function GetCapacity: Integer;
  107. procedure SetCapacity(Value: Integer); overload;
  108. function GetCount : Integer;
  109. procedure SetCount(Value: Integer);
  110. function GetItem(Index: Integer): T;
  111. procedure SetItem(Index: Integer; const Value: T);
  112. function GetEnumerator : TEnumerator<T>;
  113. public
  114. constructor Create;
  115. destructor Destroy; override;
  116. function Add(const Value: T): Integer; inline;
  117. procedure AddRange(const Values: array of T); overload;
  118. procedure AddRange(const Collection: IEnumerable<T>); overload; inline;
  119. procedure AddRange(const Collection: TEnumerable<T>); overload;
  120. procedure Insert(Index: Integer; const Value: T); inline;
  121. procedure InsertRange(Index: Integer; const Values: array of T; Count: Integer); overload;
  122. procedure InsertRange(Index: Integer; const Values: array of T); overload;
  123. procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
  124. procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;
  125. function Remove(const Value: T): Integer; inline;
  126. function RemoveItem(const Value: T; Direction: TDirection): Integer; inline;
  127. procedure Delete(Index: Integer); inline;
  128. procedure DeleteRange(AIndex, ACount: Integer); inline;
  129. function ExtractItem(const Value: T; Direction: TDirection): T; inline;
  130. function Extract(const Value: T): T; inline;
  131. function ExtractAt(Index: Integer): T; inline;
  132. procedure Exchange(Index1, Index2: Integer); inline;
  133. procedure Move(CurIndex, NewIndex: Integer); inline;
  134. function First: T; inline;
  135. function Last: T; inline;
  136. procedure Clear; inline;
  137. function Contains(const Value: T): Boolean; inline;
  138. function IndexOf(const Value: T): Integer; inline;
  139. function IndexOfItem(const Value: T; Direction: TDirection): Integer; inline;
  140. function LastIndexOf(const Value: T): Integer; inline;
  141. procedure Reverse; inline;
  142. procedure Sort; overload; inline;
  143. procedure Sort(const AComparer: IComparer<T>); overload; inline;
  144. function BinarySearch(const Item: T; out Index: Integer): Boolean; overload; inline;
  145. function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload; inline;
  146. procedure TrimExcess; inline;
  147. function ToArray: TArray<T>; inline;
  148. property Capacity: Integer read GetCapacity write SetCapacity;
  149. property Count: Integer read GetCount write SetCount;
  150. property Items[Index: Integer]: T read GetItem write SetItem; default;
  151. property List: arrayofT read GetList;
  152. procedure FromList(const aList : TList<T>);
  153. procedure FromArray(const aArray: TArray<T>);
  154. function ToList : TList<T>;
  155. function Any : Boolean; overload; virtual;
  156. function Where(const aWhereClause : string; aWhereValues : array of const) : ILinqQuery<T>; overload;
  157. function Where(const aWhereClause: string): ILinqQuery<T>; overload;
  158. function Any(const aMatchString : string; aUseRegEx : Boolean) : Boolean; overload;
  159. function Where(const aMatchString : string; aUseRegEx : Boolean) : ILinqArray<T>; overload;
  160. {$IFNDEF FPC}
  161. function Where(aPredicate : TPredicate<T>) : ILinqQuery<T>; overload;
  162. {$ENDIF}
  163. end;
  164. TxObjectList<T : class> = class(TxList<T>,IObjectList<T>)
  165. private
  166. fOwnsObjects : Boolean;
  167. procedure InternalOnNotify(Sender: TObject; const Item: T; Action: TCollectionNotification);
  168. public
  169. constructor Create(aOwnedObjects : Boolean = True);
  170. destructor Destroy; override;
  171. function Any(const aWhereClause : string; aValues : array of const) : Boolean; overload;
  172. function Where(const aWhereClause : string; aWhereValues : array of const) : ILinqQuery<T>; overload;
  173. function Where(const aWhereClause: string): ILinqQuery<T>; overload;
  174. function Where(aPredicate : TPredicate<T>): ILinqQuery<T>; overload;
  175. end;
  176. ECollectionError = class(Exception);
  177. ECollectionNotSupported = class(Exception);
  178. implementation
  179. { TXList<T> }
  180. constructor TxList<T>.Create;
  181. begin
  182. fList := TList<T>.Create;
  183. end;
  184. destructor TxList<T>.Destroy;
  185. begin
  186. fList.Free;
  187. inherited;
  188. end;
  189. function TxList<T>.Add(const Value: T): Integer;
  190. begin
  191. Result := fList.Add(Value);
  192. end;
  193. procedure TxList<T>.AddRange(const Values: array of T);
  194. begin
  195. fList.AddRange(Values);
  196. end;
  197. procedure TxList<T>.AddRange(const Collection: IEnumerable<T>);
  198. begin
  199. fList.AddRange(Collection);
  200. end;
  201. procedure TxList<T>.AddRange(const Collection: TEnumerable<T>);
  202. begin
  203. fList.AddRange(Collection);
  204. end;
  205. function TxList<T>.Any(const aMatchString: string; aUseRegEx: Boolean): Boolean;
  206. begin
  207. Result := Where(aMatchString,aUseRegEx).Any;
  208. end;
  209. function TxList<T>.Any: Boolean;
  210. begin
  211. Result := fList.Count > 0;
  212. end;
  213. function TxList<T>.BinarySearch(const Item: T; out Index: Integer): Boolean;
  214. begin
  215. Result := fList.BinarySearch(Item,Index);
  216. end;
  217. function TxList<T>.BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean;
  218. begin
  219. Result := fList.BinarySearch(Item,Index,AComparer);
  220. end;
  221. procedure TxList<T>.Clear;
  222. begin
  223. fList.Clear;
  224. end;
  225. function TxList<T>.Contains(const Value: T): Boolean;
  226. begin
  227. Result := fList.Contains(Value);
  228. end;
  229. procedure TxList<T>.Delete(Index: Integer);
  230. begin
  231. fList.Delete(Index);
  232. end;
  233. procedure TxList<T>.DeleteRange(AIndex, ACount: Integer);
  234. begin
  235. fList.DeleteRange(aIndex,aCount);
  236. end;
  237. procedure TxList<T>.Exchange(Index1, Index2: Integer);
  238. begin
  239. fList.Exchange(Index1,Index2);
  240. end;
  241. function TxList<T>.Extract(const Value: T): T;
  242. begin
  243. Result := fList.Extract(Value);
  244. end;
  245. function TxList<T>.ExtractAt(Index: Integer): T;
  246. begin
  247. Result := fList.ExtractAt(Index);
  248. end;
  249. function TxList<T>.ExtractItem(const Value: T; Direction: TDirection): T;
  250. begin
  251. Result := fList.ExtractItem(Value,Direction);
  252. end;
  253. function TxList<T>.First: T;
  254. begin
  255. Result := fList.First;
  256. end;
  257. procedure TxList<T>.FromList(const aList: TList<T>);
  258. var
  259. value : T;
  260. begin
  261. for value in aList do fList.Add(value);
  262. end;
  263. procedure TxList<T>.FromArray(const aArray: TArray<T>);
  264. var
  265. value : T;
  266. begin
  267. for value in aArray do fList.Add(value);
  268. end;
  269. function TxList<T>.GetCapacity: Integer;
  270. begin
  271. Result := fList.Capacity;
  272. end;
  273. function TxList<T>.GetCount: Integer;
  274. begin
  275. Result := fList.Count;
  276. end;
  277. function TxList<T>.GetEnumerator: TEnumerator<T>;
  278. begin
  279. Result := fList.GetEnumerator;
  280. end;
  281. function TxList<T>.GetItem(Index: Integer): T;
  282. begin
  283. Result := fList.Items[Index];
  284. end;
  285. function TxList<T>.GetList: TArray<T>;
  286. begin
  287. Result := fList.ToArray;
  288. end;
  289. function TxList<T>.IndexOf(const Value: T): Integer;
  290. begin
  291. Result := fList.IndexOf(Value);
  292. end;
  293. function TxList<T>.IndexOfItem(const Value: T; Direction: TDirection): Integer;
  294. begin
  295. Result := fList.IndexOfItem(Value,Direction);
  296. end;
  297. procedure TxList<T>.Insert(Index: Integer; const Value: T);
  298. begin
  299. fList.Insert(Index,Value);
  300. end;
  301. procedure TxList<T>.InsertRange(Index: Integer; const Collection: IEnumerable<T>);
  302. begin
  303. fList.InsertRange(Index,Collection);
  304. end;
  305. procedure TxList<T>.InsertRange(Index: Integer; const Collection: TEnumerable<T>);
  306. begin
  307. fList.InsertRange(index,Collection);
  308. end;
  309. procedure TxList<T>.InsertRange(Index: Integer; const Values: array of T; Count: Integer);
  310. begin
  311. fList.InsertRange(Index,Values,Count);
  312. end;
  313. procedure TxList<T>.InsertRange(Index: Integer; const Values: array of T);
  314. begin
  315. fList.InsertRange(index,Values);
  316. end;
  317. function TxList<T>.Last: T;
  318. begin
  319. Result := fList.Last;
  320. end;
  321. function TxList<T>.LastIndexOf(const Value: T): Integer;
  322. begin
  323. Result := fList.LastIndexOf(Value);
  324. end;
  325. procedure TxList<T>.Move(CurIndex, NewIndex: Integer);
  326. begin
  327. fList.Move(CurIndex,NewIndex);
  328. end;
  329. function TxList<T>.Remove(const Value: T): Integer;
  330. begin
  331. Result := fList.Remove(Value);
  332. end;
  333. function TxList<T>.RemoveItem(const Value: T; Direction: TDirection): Integer;
  334. begin
  335. Result := fList.RemoveItem(Value,Direction);
  336. end;
  337. procedure TxList<T>.Reverse;
  338. begin
  339. fList.Reverse;
  340. end;
  341. procedure TxList<T>.SetCapacity(Value: Integer);
  342. begin
  343. fList.Capacity := Value;
  344. end;
  345. procedure TxList<T>.SetCount(Value: Integer);
  346. begin
  347. fList.Count := Value;
  348. end;
  349. procedure TxList<T>.SetItem(Index: Integer; const Value: T);
  350. begin
  351. fList.Items[Index] := Value;
  352. end;
  353. procedure TxList<T>.Sort(const AComparer: IComparer<T>);
  354. begin
  355. fList.Sort(AComparer);
  356. end;
  357. procedure TxList<T>.Sort;
  358. begin
  359. fList.Sort;
  360. end;
  361. function TxList<T>.ToArray: TArray<T>;
  362. begin
  363. Result := fList.ToArray;
  364. end;
  365. function TxList<T>.ToList: TList<T>;
  366. var
  367. value : T;
  368. begin
  369. Result := TList<T>.Create;
  370. for value in fList do Result.Add(value);
  371. end;
  372. procedure TxList<T>.TrimExcess;
  373. begin
  374. fList.TrimExcess;
  375. end;
  376. function TxList<T>.Where(const aMatchString: string; aUseRegEx: Boolean): ILinqArray<T>;
  377. begin
  378. Result := TLinqArray<T>.Create(fList.ToArray);
  379. Result.Where(aMatchString, aUseRegEx);
  380. end;
  381. function TxList<T>.Where(const aWhereClause: string; aWhereValues: array of const): ILinqQuery<T>;
  382. begin
  383. if PTypeInfo(typeInfo(T)).Kind <> tkClass then raise ECollectionNotSupported.Create('TXList<T>.Where only supports classes. Use MatchString overload method instead!');
  384. Result := TLinqQuery<TObject>.Create(TObjectList<TObject>(Self.fList)).Where(aWhereClause,aWhereValues) as ILinqQuery<T>;
  385. end;
  386. function TxList<T>.Where(const aWhereClause: string): ILinqQuery<T>;
  387. begin
  388. if PTypeInfo(typeInfo(T)).Kind <> tkClass then raise ECollectionNotSupported.Create('TXList<T>.Where only supports classes. Use MatchString overload method instead!');
  389. Result := TLinqQuery<TObject>.Create(TObjectList<TObject>(Self.fList)).Where(aWhereClause) as ILinqQuery<T>;
  390. end;
  391. function TxList<T>.Where(aPredicate: TPredicate<T>): ILinqQuery<T>;
  392. begin
  393. if PTypeInfo(typeInfo(T)).Kind <> tkClass then raise ECollectionNotSupported.Create('TXList<T>.Where only supports classes. Use MatchString overload method instead!');
  394. Result := TLinqQuery<TObject>.Create(TObjectList<TObject>(Self.fList)).Where(TPredicate<TObject>(aPredicate)) as ILinqQuery<T>;
  395. end;
  396. { TXObjectList<T> }
  397. function TxObjectList<T>.Any(const aWhereClause: string; aValues: array of const): Boolean;
  398. var
  399. query : ILinqQuery<T>;
  400. begin
  401. query := TLinqQuery<T>.Create(Self.fList);
  402. Result := query.Where(aWhereClause,aValues).Count > 0;
  403. end;
  404. constructor TxObjectList<T>.Create(aOwnedObjects: Boolean = True);
  405. begin
  406. inherited Create;
  407. fOwnsObjects := aOwnedObjects;
  408. fList.OnNotify := InternalOnNotify;
  409. end;
  410. destructor TxObjectList<T>.Destroy;
  411. begin
  412. inherited;
  413. end;
  414. procedure TxObjectList<T>.InternalOnNotify(Sender: TObject; const Item: T; Action: TCollectionNotification);
  415. begin
  416. if (fOwnsObjects) and (Action = TCollectionNotification.cnRemoved) then
  417. begin
  418. if Assigned(Item) then Item.DisposeOf;
  419. //if PTypeInfo(typeInfo(T)).Kind = tkClass then
  420. //PObject(@Item).DisposeOf;
  421. end;
  422. end;
  423. function TxObjectList<T>.Where(const aWhereClause: string): ILinqQuery<T>;
  424. begin
  425. Result := TLinqQuery<T>.Create(Self.fList).Where(aWhereClause);
  426. end;
  427. function TxObjectList<T>.Where(const aWhereClause: string; aWhereValues: array of const): ILinqQuery<T>;
  428. begin
  429. Result := TLinqQuery<T>.Create(Self.fList).Where(aWhereClause,aWhereValues);
  430. end;
  431. function TxObjectList<T>.Where(aPredicate: TPredicate<T>): ILinqQuery<T>;
  432. begin
  433. Result := TLinqQuery<T>.Create(Self.fList).Where(aPredicate);
  434. end;
  435. end.