ghashmap.pp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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. { $define STL_INTERFACE_EXT}
  12. unit ghashmap;
  13. interface
  14. uses gvector, gutil, garrayutils;
  15. const
  16. baseFDataSize = 8; // must be > 0
  17. {$IFDEF FPUNONE}
  18. maxLoadingFactor = 1;
  19. {$ELSE}
  20. maxLoadingFactor = 1.0;
  21. {$ENDIF}
  22. {
  23. THash should have the class functions
  24. hash(a: TKey, n: SizeUInt): SizeUInt;
  25. return uniformly distributed i value in range <0,n-1> base only on arguments,
  26. n will be always power of 2
  27. equal(const AKey1, AKey2: TKey): Boolean; [when STL_INTERFACE_EXT is defined]
  28. return the boolean test for equality of the two keys. Typically this is operator=,
  29. but it doesn't have to be (e.g. case-insensitive string comparison)
  30. }
  31. type
  32. { THashmapIterator }
  33. generic THashmapIterator<TKey, TValue, T, TTable>=class
  34. public
  35. type PValue=^TValue;
  36. TIntIterator = specialize THashmapIterator<TKey, TValue, T, TTable>;
  37. var
  38. Fh,Fp:SizeUInt;
  39. FData:TTable;
  40. function Next:boolean;inline;
  41. function MoveNext:boolean;inline;
  42. function Prev:boolean;inline;
  43. function GetData:T;inline;
  44. function GetKey:TKey;inline;
  45. function GetValue:TValue;inline;
  46. function GetMutable:PValue;inline;
  47. procedure SetValue(value:TValue);inline;
  48. function GetEnumerator : TIntIterator; inline;
  49. property Data:T read GetData;
  50. property Key:TKey read GetKey;
  51. property Value:TValue read GetValue write SetValue;
  52. property MutableValue:PValue read GetMutable;
  53. property Current : T read GetData;
  54. end;
  55. { THashmap }
  56. generic THashmap<TKey, TValue, Thash>=class
  57. public
  58. type
  59. TPair=record
  60. Value:TValue;
  61. Key:TKey;
  62. end;
  63. var
  64. private
  65. type
  66. TContainer = specialize TVector<TPair>;
  67. TTable = specialize TVector<TContainer>;
  68. var
  69. FData:TTable;
  70. FDataSize:SizeUInt;
  71. procedure EnlargeTable;
  72. public
  73. type
  74. TIterator = specialize THashmapIterator<TKey, TValue, TPair, TTable>;
  75. constructor Create;
  76. destructor Destroy;override;
  77. procedure insert(key:TKey;value:TValue);inline;
  78. function contains(key:TKey):boolean;inline;
  79. function Size:SizeUInt;inline;
  80. procedure delete(key:TKey);inline;
  81. procedure erase(iter:TIterator);inline;
  82. function IsEmpty:boolean;inline;
  83. function GetData(key:TKey):TValue;inline;
  84. function GetValue(key:TKey;out value:TValue):boolean;inline;
  85. function Iterator:TIterator;
  86. function getenumerator :TIterator;
  87. property Items[i : TKey]: TValue read GetData write Insert; default;
  88. end;
  89. implementation
  90. function THashmap.Size: SizeUInt;
  91. begin
  92. Size:=FDataSize;
  93. end;
  94. destructor THashmap.Destroy;
  95. var i:SizeUInt;
  96. begin
  97. i:=0;
  98. while i < FData.size do
  99. begin
  100. (FData[i]).Destroy;
  101. inc(i);
  102. end;
  103. FData.Destroy;
  104. end;
  105. function THashmap.IsEmpty: boolean;
  106. begin
  107. IsEmpty := Size()=0;
  108. end;
  109. procedure THashmap.EnlargeTable;
  110. var i,j,h,oldDataSize:SizeUInt;
  111. curbucket:TContainer;
  112. value:TPair;
  113. begin
  114. //Assert(oldDataSize>0);
  115. oldDataSize:=FData.size;
  116. FData.resize(FData.size*2);
  117. for i:=oldDataSize to FData.size-1 do
  118. FData[i] := TContainer.create;
  119. for i:=oldDataSize-1 downto 0 do begin
  120. curbucket:=FData[i];
  121. j := 0;
  122. while j < curbucket.size do begin
  123. h:=THash.hash(curbucket[j].key,FData.size);
  124. if (h <> i) then begin
  125. if (j+1) < curbucket.size then begin
  126. value:=curbucket[j];
  127. curbucket[j]:= curbucket.back;
  128. (FData[h]).pushback(value);
  129. end else
  130. (FData[h]).pushback(curbucket[j]);
  131. curbucket.popback;
  132. end else
  133. inc(j);
  134. end;
  135. end;
  136. end;
  137. constructor THashmap.Create;
  138. var i: SizeUInt;
  139. begin
  140. FDataSize:=0;
  141. FData:=TTable.create;
  142. FData.resize(baseFDataSize);
  143. for i:=0 to baseFDataSize-1 do
  144. FData[i]:=TContainer.create;
  145. end;
  146. function THashmap.contains(key: TKey): boolean;
  147. var i,bs:SizeUInt;
  148. curbucket:TContainer;
  149. begin
  150. curbucket:=FData[THash.hash(key,FData.size)];
  151. bs:=curbucket.size;
  152. i:=0;
  153. while i < bs do begin
  154. {$ifdef STL_INTERFACE_EXT}
  155. if THash.equal(curbucket[i].Key, key) then exit(true);
  156. {$else}
  157. if (curbucket[i].Key = key) then exit(true);
  158. {$endif}
  159. inc(i);
  160. end;
  161. exit(false);
  162. end;
  163. function THashmap.GetData(key: TKey): TValue;
  164. var i,bs:SizeUInt;
  165. curbucket:TContainer;
  166. begin
  167. curbucket:=FData[THash.hash(key,FData.size)];
  168. bs:=curbucket.size;
  169. i:=0;
  170. while i < bs do begin
  171. {$ifdef STL_INTERFACE_EXT}
  172. if THash.equal(curbucket[i].Key, key) then exit(curbucket[i].Value);
  173. {$else}
  174. if (curbucket[i].Key = key) then exit(curbucket[i].Value);
  175. {$endif}
  176. inc(i);
  177. end;
  178. Result:=Default(TValue);
  179. // exception?
  180. end;
  181. function THashmap.GetValue(key: TKey; out value: TValue): boolean;
  182. var i,bs:SizeUInt;
  183. curbucket:TContainer;
  184. begin
  185. curbucket:=FData[THash.hash(key,FData.size)];
  186. bs:=curbucket.size;
  187. i:=0;
  188. while i < bs do begin
  189. {$ifdef STL_INTERFACE_EXT}
  190. if THash.equal(curbucket[i].Key, key) then begin
  191. {$else}
  192. if (curbucket[i].Key = key) then begin
  193. {$endif}
  194. value:=curbucket[i].Value;
  195. exit(true);
  196. end;
  197. inc(i);
  198. end;
  199. exit(false);
  200. end;
  201. procedure THashmap.insert(key: TKey; value: TValue);
  202. var pair:TPair;
  203. i,bs:SizeUInt;
  204. curbucket:TContainer;
  205. begin
  206. curbucket:=FData[THash.hash(key,FData.size)];
  207. bs:=curbucket.size;
  208. i:=0;
  209. while i < bs do begin
  210. {$ifdef STL_INTERFACE_EXT}
  211. if THash.equal(curbucket[i].Key, key) then begin
  212. {$else}
  213. if (curbucket[i].Key = key) then begin
  214. {$endif}
  215. (curbucket.mutable[i])^.value := value;
  216. exit;
  217. end;
  218. inc(i);
  219. end;
  220. pair.Key := key;
  221. pair.Value := value;
  222. inc(FDataSize);
  223. curbucket.pushback(pair);
  224. if (FDataSize > maxLoadingFactor*FData.size) then
  225. EnlargeTable;
  226. end;
  227. procedure THashmap.delete(key: TKey);
  228. var i,bs:SizeUInt;
  229. curbucket:TContainer;
  230. begin
  231. curbucket:=FData[THash.hash(key,FData.size)];
  232. bs:=curbucket.size;
  233. i:=0;
  234. while i < bs do begin
  235. {$ifdef STL_INTERFACE_EXT}
  236. if THash.equal(curbucket[i].Key, key) then begin
  237. {$else}
  238. if (curbucket[i].Key = key) then begin
  239. {$endif}
  240. //if (i+1) < bs then
  241. curbucket[i] := curbucket.back;
  242. curbucket.popback;
  243. dec(FDataSize);
  244. exit;
  245. end;
  246. inc(i);
  247. end;
  248. end;
  249. procedure THashmap.erase(iter: TIterator);
  250. var curbucket:TContainer;
  251. begin
  252. curbucket:=FData[iter.Fh];
  253. //if (iter.Fp+1) < curbucket.size then
  254. curbucket[iter.Fp] := curbucket.back;
  255. curbucket.popback;
  256. dec(FDataSize);
  257. iter.Prev;
  258. end;
  259. function THashmapIterator.Next: boolean;
  260. begin
  261. Assert(Fh < FData.size); // assumes FData.size>0 (i.e. buckets don't shrink) and cannot call Next again after reaching end
  262. inc(Fp);
  263. if (Fp < (FData[Fh]).size) then
  264. exit(true);
  265. Fp:=0; Inc(Fh);
  266. while Fh < FData.size do begin
  267. if ((FData[Fh]).size > 0) then
  268. exit(true);
  269. Inc(Fh);
  270. end;
  271. //Assert((Fp = 0) and (Fh = FData.size));
  272. exit(false);
  273. end;
  274. function THashmapIterator.MoveNext: boolean;
  275. begin
  276. Assert(Fh < FData.size); // assumes FData.size>0 (i.e. buckets don't shrink) and cannot call Next again after reaching end
  277. inc(Fp);
  278. if (Fp < (FData[Fh]).size) then
  279. exit(true);
  280. Fp:=0; Inc(Fh);
  281. while Fh < FData.size do begin
  282. if ((FData[Fh]).size > 0) then
  283. exit(true);
  284. Inc(Fh);
  285. end;
  286. //Assert((Fp = 0) and (Fh = FData.size));
  287. exit(false);
  288. end;
  289. function THashmapIterator.Prev: boolean;
  290. var bs:SizeUInt;
  291. begin
  292. if (Fp > 0) then begin
  293. dec(Fp);
  294. exit(true);
  295. end;
  296. while Fh > 0 do begin
  297. Dec(Fh);
  298. bs:=(FData[Fh]).size;
  299. if (bs > 0) then begin
  300. Fp:=bs-1;
  301. exit(true);
  302. end;
  303. end;
  304. //Assert((Fp = 0) and (Fh = 0));
  305. exit(false);
  306. end;
  307. function THashmapIterator.GetData: T;
  308. begin
  309. GetData:=(FData[Fh])[Fp];
  310. end;
  311. function THashmap.Iterator: TIterator;
  312. var h,p:SizeUInt;
  313. begin
  314. h:=0;
  315. p:=0;
  316. while h < FData.size do begin
  317. if ((FData[h]).size > 0) then break;
  318. inc(h);
  319. end;
  320. if (h = FData.size) then exit(nil);
  321. Iterator := TIterator.create;
  322. Iterator.Fh := h;
  323. Iterator.Fp := p;
  324. Iterator.FData := FData;
  325. end;
  326. function THashmap.getenumerator: TIterator;
  327. begin
  328. result:=iterator;
  329. end;
  330. function THashmapIterator.GetKey: TKey;
  331. begin
  332. GetKey:=((FData[Fh])[Fp]).Key;
  333. end;
  334. function THashmapIterator.GetValue: TValue;
  335. begin
  336. GetValue:=((FData[Fh])[Fp]).Value;
  337. end;
  338. function THashmapIterator.GetMutable: PValue;
  339. begin
  340. GetMutable:=@((FData[Fh]).Mutable[Fp]^.Value);
  341. end;
  342. procedure THashmapIterator.SetValue(value:TValue);
  343. begin
  344. ((FData[Fh]).mutable[Fp])^.Value := value;
  345. end;
  346. function THashmapIterator.getenumerator: TIntIterator;
  347. begin
  348. result:=self;
  349. end;
  350. end.