ghashmap.pp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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. generic THashmapIterator<TKey, TValue, T, TTable>=class
  33. public
  34. type PValue=^TValue;
  35. var
  36. Fh,Fp:SizeUInt;
  37. FData:TTable;
  38. function Next:boolean;inline;
  39. function Prev:boolean;inline;
  40. function GetData:T;inline;
  41. function GetKey:TKey;inline;
  42. function GetValue:TValue;inline;
  43. function GetMutable:PValue;inline;
  44. procedure SetValue(value:TValue);inline;
  45. property Data:T read GetData;
  46. property Key:TKey read GetKey;
  47. property Value:TValue read GetValue write SetValue;
  48. property MutableValue:PValue read GetMutable;
  49. end;
  50. generic THashmap<TKey, TValue, Thash>=class
  51. public
  52. type
  53. TPair=record
  54. Value:TValue;
  55. Key:TKey;
  56. end;
  57. var
  58. private
  59. type
  60. TContainer = specialize TVector<TPair>;
  61. TTable = specialize TVector<TContainer>;
  62. var
  63. FData:TTable;
  64. FDataSize:SizeUInt;
  65. procedure EnlargeTable;
  66. public
  67. type
  68. TIterator = specialize THashmapIterator<TKey, TValue, TPair, TTable>;
  69. constructor create;
  70. destructor destroy;override;
  71. procedure insert(key:TKey;value:TValue);inline;
  72. function contains(key:TKey):boolean;inline;
  73. function size:SizeUInt;inline;
  74. procedure delete(key:TKey);inline;
  75. procedure erase(iter:TIterator);inline;
  76. function IsEmpty:boolean;inline;
  77. function GetData(key:TKey):TValue;inline;
  78. function GetValue(key:TKey;out value:TValue):boolean;inline;
  79. property Items[i : TKey]: TValue read GetData write Insert; default;
  80. function Iterator:TIterator;
  81. end;
  82. implementation
  83. function THashmap.Size: SizeUInt;
  84. begin
  85. Size:=FDataSize;
  86. end;
  87. destructor THashmap.Destroy;
  88. var i:SizeUInt;
  89. begin
  90. i:=0;
  91. while i < FData.size do
  92. begin
  93. (FData[i]).Destroy;
  94. inc(i);
  95. end;
  96. FData.Destroy;
  97. end;
  98. function THashmap.IsEmpty(): boolean;
  99. begin
  100. IsEmpty := Size()=0;
  101. end;
  102. procedure THashmap.EnlargeTable;
  103. var i,j,h,oldDataSize:SizeUInt;
  104. curbucket:TContainer;
  105. value:TPair;
  106. begin
  107. //Assert(oldDataSize>0);
  108. oldDataSize:=FData.size;
  109. FData.resize(FData.size*2);
  110. for i:=oldDataSize to FData.size-1 do
  111. FData[i] := TContainer.create;
  112. for i:=oldDataSize-1 downto 0 do begin
  113. curbucket:=FData[i];
  114. j := 0;
  115. while j < curbucket.size do begin
  116. h:=THash.hash(curbucket[j].key,FData.size);
  117. if (h <> i) then begin
  118. if (j+1) < curbucket.size then begin
  119. value:=curbucket[j];
  120. curbucket[j]:= curbucket.back;
  121. (FData[h]).pushback(value);
  122. end else
  123. (FData[h]).pushback(curbucket[j]);
  124. curbucket.popback;
  125. end else
  126. inc(j);
  127. end;
  128. end;
  129. end;
  130. constructor THashmap.create;
  131. var i: SizeUInt;
  132. begin
  133. FDataSize:=0;
  134. FData:=TTable.create;
  135. FData.resize(baseFDataSize);
  136. for i:=0 to baseFDataSize-1 do
  137. FData[i]:=TContainer.create;
  138. end;
  139. function THashmap.contains(key: TKey): boolean;
  140. var i,bs:SizeUInt;
  141. curbucket:TContainer;
  142. begin
  143. curbucket:=FData[THash.hash(key,FData.size)];
  144. bs:=curbucket.size;
  145. i:=0;
  146. while i < bs do begin
  147. {$ifdef STL_INTERFACE_EXT}
  148. if THash.equal(curbucket[i].Key, key) then exit(true);
  149. {$else}
  150. if (curbucket[i].Key = key) then exit(true);
  151. {$endif}
  152. inc(i);
  153. end;
  154. exit(false);
  155. end;
  156. function THashmap.GetData(key: TKey): TValue;
  157. var i,bs:SizeUInt;
  158. curbucket:TContainer;
  159. begin
  160. curbucket:=FData[THash.hash(key,FData.size)];
  161. bs:=curbucket.size;
  162. i:=0;
  163. while i < bs do begin
  164. {$ifdef STL_INTERFACE_EXT}
  165. if THash.equal(curbucket[i].Key, key) then exit(curbucket[i].Value);
  166. {$else}
  167. if (curbucket[i].Key = key) then exit(curbucket[i].Value);
  168. {$endif}
  169. inc(i);
  170. end;
  171. // exception?
  172. end;
  173. function THashmap.GetValue(key: TKey; out value: TValue): boolean;
  174. var i,bs:SizeUInt;
  175. curbucket:TContainer;
  176. begin
  177. curbucket:=FData[THash.hash(key,FData.size)];
  178. bs:=curbucket.size;
  179. i:=0;
  180. while i < bs do begin
  181. {$ifdef STL_INTERFACE_EXT}
  182. if THash.equal(curbucket[i].Key, key) then begin
  183. {$else}
  184. if (curbucket[i].Key = key) then begin
  185. {$endif}
  186. value:=curbucket[i].Value;
  187. exit(true);
  188. end;
  189. inc(i);
  190. end;
  191. exit(false);
  192. end;
  193. procedure THashmap.insert(key: TKey; value: TValue);
  194. var pair:TPair;
  195. i,bs:SizeUInt;
  196. curbucket:TContainer;
  197. begin
  198. curbucket:=FData[THash.hash(key,FData.size)];
  199. bs:=curbucket.size;
  200. i:=0;
  201. while i < bs do begin
  202. {$ifdef STL_INTERFACE_EXT}
  203. if THash.equal(curbucket[i].Key, key) then begin
  204. {$else}
  205. if (curbucket[i].Key = key) then begin
  206. {$endif}
  207. (curbucket.mutable[i])^.value := value;
  208. exit;
  209. end;
  210. inc(i);
  211. end;
  212. pair.Key := key;
  213. pair.Value := value;
  214. inc(FDataSize);
  215. curbucket.pushback(pair);
  216. if (FDataSize > maxLoadingFactor*FData.size) then
  217. EnlargeTable;
  218. end;
  219. procedure THashmap.delete(key: TKey);
  220. var i,bs:SizeUInt;
  221. curbucket:TContainer;
  222. begin
  223. curbucket:=FData[THash.hash(key,FData.size)];
  224. bs:=curbucket.size;
  225. i:=0;
  226. while i < bs do begin
  227. {$ifdef STL_INTERFACE_EXT}
  228. if THash.equal(curbucket[i].Key, key) then begin
  229. {$else}
  230. if (curbucket[i].Key = key) then begin
  231. {$endif}
  232. //if (i+1) < bs then
  233. curbucket[i] := curbucket.back;
  234. curbucket.popback;
  235. dec(FDataSize);
  236. exit;
  237. end;
  238. inc(i);
  239. end;
  240. end;
  241. procedure THashmap.erase(iter: TIterator);
  242. var curbucket:TContainer;
  243. begin
  244. curbucket:=FData[iter.Fh];
  245. //if (iter.Fp+1) < curbucket.size then
  246. curbucket[iter.Fp] := curbucket.back;
  247. curbucket.popback;
  248. dec(FDataSize);
  249. iter.Prev;
  250. end;
  251. function THashmapIterator.Next: boolean;
  252. begin
  253. Assert(Fh < FData.size); // assumes FData.size>0 (i.e. buckets don't shrink) and cannot call Next again after reaching end
  254. inc(Fp);
  255. if (Fp < (FData[Fh]).size) then
  256. exit(true);
  257. Fp:=0; Inc(Fh);
  258. while Fh < FData.size do begin
  259. if ((FData[Fh]).size > 0) then
  260. exit(true);
  261. Inc(Fh);
  262. end;
  263. //Assert((Fp = 0) and (Fh = FData.size));
  264. exit(false);
  265. end;
  266. function THashmapIterator.Prev: boolean;
  267. var bs:SizeUInt;
  268. begin
  269. if (Fp > 0) then begin
  270. dec(Fp);
  271. exit(true);
  272. end;
  273. while Fh > 0 do begin
  274. Dec(Fh);
  275. bs:=(FData[Fh]).size;
  276. if (bs > 0) then begin
  277. Fp:=bs-1;
  278. exit(true);
  279. end;
  280. end;
  281. //Assert((Fp = 0) and (Fh = 0));
  282. exit(false);
  283. end;
  284. function THashmapIterator.GetData: T;
  285. begin
  286. GetData:=(FData[Fh])[Fp];
  287. end;
  288. function THashmap.Iterator: TIterator;
  289. var h,p:SizeUInt;
  290. begin
  291. h:=0;
  292. p:=0;
  293. while h < FData.size do begin
  294. if ((FData[h]).size > 0) then break;
  295. inc(h);
  296. end;
  297. if (h = FData.size) then exit(nil);
  298. Iterator := TIterator.create;
  299. Iterator.Fh := h;
  300. Iterator.Fp := p;
  301. Iterator.FData := FData;
  302. end;
  303. function THashmapIterator.GetKey: TKey;
  304. begin
  305. GetKey:=((FData[Fh])[Fp]).Key;
  306. end;
  307. function THashmapIterator.GetValue: TValue;
  308. begin
  309. GetValue:=((FData[Fh])[Fp]).Value;
  310. end;
  311. function THashmapIterator.GetMutable: PValue;
  312. begin
  313. GetMutable:=@((FData[Fh]).Mutable[Fp]^.Value);
  314. end;
  315. procedure THashmapIterator.SetValue(value:TValue);
  316. begin
  317. ((FData[Fh]).mutable[Fp])^.Value := value;
  318. end;
  319. end.