Quick.Lists.pas 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. { ***************************************************************************
  2. Copyright (c) 2016-2018 Kike Pérez
  3. Unit : Quick.Lists
  4. Description : Generic Lists functions
  5. Author : Kike Pérez
  6. Version : 1.0
  7. Created : 04/11/2018
  8. Modified : 04/1º/2018
  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.Lists;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. Classes,
  26. SysUtils,
  27. RTTI,
  28. System.Generics.Collections,
  29. System.Generics.Defaults;
  30. type
  31. TSearchDictionary<TKey,TValue> = class(TObjectDictionary<TKey,TValue>)
  32. private
  33. fIndexName : string;
  34. fFieldName : string;
  35. public
  36. property IndexName : string read fIndexName write fIndexName;
  37. property FieldName : string read fFieldName write fFieldName;
  38. end;
  39. TIndexList<T> = class
  40. private
  41. fList : TList<TSearchDictionary<Variant,T>>;
  42. fDictionaryIndex : TObjectDictionary<string,TSearchDictionary<Variant,T>>;
  43. public
  44. constructor Create;
  45. destructor Destroy; override;
  46. property List : TList<TSearchDictionary<Variant,T>> read fList;
  47. function Get(const aIndexName : string) : TSearchDictionary<Variant,T>;
  48. procedure Add(const aIndexName, aFieldName : string);
  49. procedure Remove(const aIndexName : string);
  50. end;
  51. TIndexedObjectList<T: class> = class(TList<T>)
  52. private
  53. fOwnsObjects: Boolean;
  54. fIndexes : TIndexList<T>;
  55. protected
  56. procedure Notify(const Value: T; Action: TCollectionNotification); override;
  57. public
  58. constructor Create(aOwnsObjects: Boolean = True); overload;
  59. constructor Create(const aComparer: IComparer<T>; aOwnsObjects: Boolean = True); overload;
  60. constructor Create(const aCollection: TEnumerable<T>; aOwnsObjects: Boolean = True); overload;
  61. destructor Destroy; override;
  62. property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
  63. property Indexes : TIndexList<T> read fIndexes;
  64. function Get(const aIndexName : string; aValue : Variant) : T;
  65. end;
  66. implementation
  67. { TIndexedObjectList<T> }
  68. constructor TIndexedObjectList<T>.Create(aOwnsObjects: Boolean);
  69. begin
  70. inherited Create;
  71. FOwnsObjects := aOwnsObjects;
  72. fIndexes := TIndexList<T>.Create;
  73. end;
  74. constructor TIndexedObjectList<T>.Create(const aComparer: IComparer<T>; aOwnsObjects: Boolean);
  75. begin
  76. inherited Create(aComparer);
  77. FOwnsObjects := aOwnsObjects;
  78. fIndexes := TIndexList<T>.Create;
  79. end;
  80. constructor TIndexedObjectList<T>.Create(const aCollection: TEnumerable<T>; aOwnsObjects: Boolean);
  81. begin
  82. inherited Create(aCollection);
  83. FOwnsObjects := aOwnsObjects;
  84. fIndexes := TIndexList<T>.Create;
  85. end;
  86. procedure TIndexedObjectList<T>.Notify(const Value: T; Action: TCollectionNotification);
  87. var
  88. sindex : TSearchDictionary<Variant,T>;
  89. ctx: TRttiContext;
  90. rtype: TRttiType;
  91. rfield: TRttiField;
  92. propvalue : TValue;
  93. begin
  94. inherited;
  95. if Action = cnAdded then
  96. begin
  97. for sindex in fIndexes.List do
  98. begin
  99. rtype := ctx.GetType(TypeInfo(T));
  100. rfield := rtype.GetField(sindex.FieldName);
  101. if rfield = nil then raise Exception.CreateFmt('Cannot add value to "%s" search dictionary!',[sindex.IndexName]);
  102. propvalue := rfield.GetValue(TObject(Value));
  103. sindex.Add(propvalue.AsVariant,Value);
  104. end;
  105. end;
  106. //remove object if owned
  107. if OwnsObjects and (Action = cnRemoved) then
  108. begin
  109. for sindex in fIndexes.List do
  110. begin
  111. rtype := ctx.GetType(TypeInfo(T));
  112. rfield := rtype.GetField(sindex.FieldName);
  113. if rfield = nil then raise Exception.CreateFmt('Cannot remove value to "%s" search dictionary!',[sindex.IndexName]);
  114. propvalue := rfield.GetValue(TObject(Value));
  115. sindex.Remove(propvalue.AsVariant);
  116. end;
  117. Value.DisposeOf;
  118. end;
  119. end;
  120. destructor TIndexedObjectList<T>.Destroy;
  121. begin
  122. inherited;
  123. fIndexes.Free;
  124. end;
  125. function TIndexedObjectList<T>.Get(const aIndexName: string; aValue : Variant): T;
  126. var
  127. sindex : TSearchDictionary<Variant,T>;
  128. begin
  129. Result := nil;
  130. sindex := fIndexes.Get(aIndexName.ToLower);
  131. if sindex <> nil then sindex.TryGetValue(aValue,Result)
  132. else raise Exception.CreateFmt('Index "%s" not found!',[aIndexName]);
  133. end;
  134. { TIndexList<T> }
  135. procedure TIndexList<T>.Add(const aIndexName, aFieldName: string);
  136. var
  137. sdict : TSearchDictionary<Variant,T>;
  138. ctx: TRttiContext;
  139. rtype: TRttiType;
  140. rfield: TRttiField;
  141. begin
  142. rtype := ctx.GetType(TypeInfo(T));
  143. rfield := rtype.GetField(aFieldName);
  144. if rfield = nil then raise Exception.CreateFmt('Not found field "%s" to create a search dictionary!',[aFieldName]);
  145. sdict := TSearchDictionary<Variant,T>.Create;
  146. sdict.IndexName := aIndexName;
  147. sdict.FieldName := aFieldName;
  148. fList.Add(sdict);
  149. fDictionaryIndex.Add(aIndexName.ToLower,sdict);
  150. end;
  151. procedure TIndexList<T>.Remove(const aIndexName: string);
  152. var
  153. sdict : TSearchDictionary<Variant,T>;
  154. begin
  155. if not fDictionaryIndex.ContainsKey(aIndexName) then raise Exception.CreateFmt('Cannot remove an inexistent "%s" search dictionary!',[aIndexName]);
  156. fList.Remove(sdict);
  157. fDictionaryIndex.Remove(aIndexName.ToLower);
  158. sdict.Free;
  159. end;
  160. constructor TIndexList<T>.Create;
  161. begin
  162. fList := TList<TSearchDictionary<Variant,T>>.Create;
  163. fDictionaryIndex := TObjectDictionary<string,TSearchDictionary<Variant,T>>.Create;
  164. end;
  165. destructor TIndexList<T>.Destroy;
  166. var
  167. sindex : TSearchDictionary<Variant,T>;
  168. begin
  169. for sindex in fList do sindex.Free;
  170. fList.Free;
  171. fDictionaryIndex.Free;
  172. inherited;
  173. end;
  174. function TIndexList<T>.Get(const aIndexName: string): TSearchDictionary<Variant, T>;
  175. begin
  176. Result := nil;
  177. fDictionaryIndex.TryGetValue(aIndexName,Result);
  178. end;
  179. end.