generics.hashes.pas 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490
  1. {
  2. This file is part of the Free Pascal/NewPascal run time library.
  3. Copyright (c) 2014 by Maciej Izak (hnb)
  4. member of the NewPascal development team (http://newpascal.org)
  5. Copyright(c) 2004-2018 DaThoX
  6. It contains the generics collections library
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. Acknowledgment
  13. Thanks to Sphere 10 Software (http://sphere10.com) for sponsoring
  14. many new types and major refactoring of entire library.
  15. Thanks to mORMot (http://synopse.info) project for the best implementations
  16. of hashing functions like crc32c and xxHash32 :)
  17. **********************************************************************}
  18. unit Generics.Hashes;
  19. {$MODE DELPHI}{$H+}
  20. {$POINTERMATH ON}
  21. {$MACRO ON}
  22. {$COPERATORS ON}
  23. {$OVERFLOWCHECKS OFF}
  24. {$RANGECHECKS OFF}
  25. interface
  26. uses
  27. Classes, SysUtils;
  28. { Warning: the following set of macro code
  29. that decides to use assembler or normal code
  30. needs to stay after the _INTERFACE keyword
  31. because FPC_PIC macro is only set after this keyword,
  32. as it can be modified before by the global $PIC preprocessor directive.
  33. Pierre Muller 2018/07/04 }
  34. {$ifdef FPC_PIC}
  35. {$define DISABLE_X86_CPUINTEL}
  36. {$endif FPC_PIC}
  37. {$if defined(OPENBSD) or defined(EMX) or defined(OS2)}
  38. { These targets have old GNU assemblers that }
  39. { do not support all instructions used in assembler code below }
  40. {$define DISABLE_X86_CPUINTEL}
  41. {$endif}
  42. {$ifdef CPU64}
  43. {$define PUREPASCAL}
  44. {$ifdef CPUX64}
  45. {$define CPUINTEL}
  46. {$ASMMODE INTEL}
  47. {$endif CPUX64}
  48. {$else}
  49. {$ifdef CPUX86}
  50. {$ifndef DISABLE_X86_CPUINTEL}
  51. {$define CPUINTEL}
  52. {$ASMMODE INTEL}
  53. {$else}
  54. { Assembler code uses references to static
  55. variables with are not PIC ready }
  56. {$define PUREPASCAL}
  57. {$endif}
  58. {$else CPUX86}
  59. {$define PUREPASCAL}
  60. {$endif}
  61. {$endif CPU64}
  62. // Original version of Bob Jenkins Hash
  63. // http://burtleburtle.net/bob/c/lookup3.c
  64. function HashWord(
  65. AKey: PLongWord; //* the key, an array of uint32_t values */
  66. ALength: SizeInt; //* the length of the key, in uint32_ts */
  67. AInitVal: UInt32): UInt32; //* the previous hash, or an arbitrary value */
  68. procedure HashWord2 (
  69. AKey: PLongWord; //* the key, an array of uint32_t values */
  70. ALength: SizeInt; //* the length of the key, in uint32_ts */
  71. var APrimaryHashAndInitVal: UInt32; //* IN: seed OUT: primary hash value */
  72. var ASecondaryHashAndInitVal: UInt32); //* IN: more seed OUT: secondary hash value */
  73. function HashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): UInt32;
  74. procedure HashLittle2(
  75. AKey: Pointer; //* the key to hash */
  76. ALength: SizeInt; //* length of the key */
  77. var APrimaryHashAndInitVal: UInt32; //* IN: primary initval, OUT: primary hash */
  78. var ASecondaryHashAndInitVal: UInt32); //* IN: secondary initval, OUT: secondary hash */
  79. function DelphiHashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): Int32;
  80. procedure DelphiHashLittle2(AKey: Pointer; ALength: SizeInt; var APrimaryHashAndInitVal, ASecondaryHashAndInitVal: UInt32);
  81. // hash function from fstl
  82. function SimpleChecksumHash(AKey: Pointer; ALength: SizeInt): UInt32;
  83. // some other hashes
  84. // http://stackoverflow.com/questions/14409466/simple-hash-functions
  85. // http://www.partow.net/programming/hashfunctions/
  86. // http://en.wikipedia.org/wiki/List_of_hash_functions
  87. // http://www.cse.yorku.ca/~oz/hash.html
  88. // https://code.google.com/p/hedgewars/source/browse/hedgewars/adler32.pas
  89. function Adler32(AKey: Pointer; ALength: SizeInt): UInt32;
  90. function sdbm(AKey: Pointer; ALength: SizeInt): UInt32;
  91. function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal;{$IFNDEF CPUINTEL}inline;{$ENDIF}
  92. // pure pascal implementation of xxHash32
  93. function xxHash32Pascal(crc: cardinal; P: Pointer; len: integer): cardinal;
  94. type
  95. THasher = function(crc: cardinal; buf: Pointer; len: cardinal): cardinal;
  96. var
  97. crc32c: THasher;
  98. mORMotHasher: THasher;
  99. implementation
  100. {$ifdef CPUINTEL}
  101. uses
  102. cpu;
  103. {$endif CPUINTEL}
  104. function SimpleChecksumHash(AKey: Pointer; ALength: SizeInt): UInt32;
  105. var
  106. i: Integer;
  107. ABuffer: PUInt8 absolute AKey;
  108. begin
  109. Result := 0;
  110. for i := 0 to ALength - 1 do
  111. Inc(Result,ABuffer[i]);
  112. end;
  113. function Adler32(AKey: Pointer; ALength: SizeInt): UInt32;
  114. const
  115. MOD_ADLER = 65521;
  116. var
  117. ABuffer: PUInt8 absolute AKey;
  118. a: UInt32 = 1;
  119. b: UInt32 = 0;
  120. n: Integer;
  121. begin
  122. for n := 0 to ALength -1 do
  123. begin
  124. a := (a + ABuffer[n]) mod MOD_ADLER;
  125. b := (b + a) mod MOD_ADLER;
  126. end;
  127. Result := (b shl 16) or a;
  128. end;
  129. function sdbm(AKey: Pointer; ALength: SizeInt): UInt32;
  130. var
  131. c: PUInt8 absolute AKey;
  132. i: Integer;
  133. begin
  134. Result := 0;
  135. c := AKey;
  136. for i := 0 to ALength - 1 do
  137. begin
  138. Result := c^ + (Result shl 6) + (Result shl 16) {%H-}- Result;
  139. Inc(c);
  140. end;
  141. end;
  142. { BobJenkinsHash }
  143. {$define mix_abc :=
  144. a -= c; a := a xor (((c)shl(4)) or ((c)shr(32-(4)))); c += b;
  145. b -= a; b := b xor (((a)shl(6)) or ((a)shr(32-(6)))); a += c;
  146. c -= b; c := c xor (((b)shl(8)) or ((b)shr(32-(8)))); b += a;
  147. a -= c; a := a xor (((c)shl(16)) or ((c)shr(32-(16)))); c += b;
  148. b -= a; b := b xor (((a)shl(19)) or ((a)shr(32-(19)))); a += c;
  149. c -= b; c := c xor (((b)shl(4)) or ((b)shr(32-(4)))); b += a
  150. }
  151. {$define final_abc :=
  152. c := c xor b; c -= (((b)shl(14)) or ((b)shr(32-(14))));
  153. a := a xor c; a -= (((c)shl(11)) or ((c)shr(32-(11))));
  154. b := b xor a; b -= (((a)shl(25)) or ((a)shr(32-(25))));
  155. c := c xor b; c -= (((b)shl(16)) or ((b)shr(32-(16))));
  156. a := a xor c; a -= (((c)shl(4)) or ((c)shr(32-(4))));
  157. b := b xor a; b -= (((a)shl(14)) or ((a)shr(32-(14))));
  158. c := c xor b; c -= (((b)shl(24)) or ((b)shr(32-(24))))
  159. }
  160. function HashWord(
  161. AKey: PLongWord; //* the key, an array of uint32_t values */
  162. ALength: SizeInt; //* the length of the key, in uint32_ts */
  163. AInitVal: UInt32): UInt32; //* the previous hash, or an arbitrary value */
  164. var
  165. a,b,c: UInt32;
  166. label
  167. Case0, Case1, Case2, Case3;
  168. begin
  169. //* Set up the internal state */
  170. a := $DEADBEEF + (UInt32(ALength) shl 2) + AInitVal;
  171. b := a;
  172. c := b;
  173. //*------------------------------------------------- handle most of the key */
  174. while ALength > 3 do
  175. begin
  176. a += AKey[0];
  177. b += AKey[1];
  178. c += AKey[2];
  179. mix_abc;
  180. ALength -= 3;
  181. AKey += 3;
  182. end;
  183. //*------------------------------------------- handle the last 3 uint32_t's */
  184. case ALength of //* all the case statements fall through */
  185. 3: goto Case3;
  186. 2: goto Case2;
  187. 1: goto Case1;
  188. 0: goto Case0;
  189. end;
  190. Case3: c+=AKey[2];
  191. Case2: b+=AKey[1];
  192. Case1: a+=AKey[0];
  193. final_abc;
  194. Case0: //* case 0: nothing left to add */
  195. //*------------------------------------------------------ report the result */
  196. Result := c;
  197. end;
  198. procedure HashWord2 (
  199. AKey: PLongWord; //* the key, an array of uint32_t values */
  200. ALength: SizeInt; //* the length of the key, in uint32_ts */
  201. var APrimaryHashAndInitVal: UInt32; //* IN: seed OUT: primary hash value */
  202. var ASecondaryHashAndInitVal: UInt32); //* IN: more seed OUT: secondary hash value */
  203. var
  204. a,b,c: UInt32;
  205. label
  206. Case0, Case1, Case2, Case3;
  207. begin
  208. //* Set up the internal state */
  209. a := $deadbeef + (UInt32(ALength shl 2)) + APrimaryHashAndInitVal;
  210. b := a;
  211. c := b;
  212. c += ASecondaryHashAndInitVal;
  213. //*------------------------------------------------- handle most of the key */
  214. while ALength > 3 do
  215. begin
  216. a += AKey[0];
  217. b += AKey[1];
  218. c += AKey[2];
  219. mix_abc;
  220. ALength -= 3;
  221. AKey += 3;
  222. end;
  223. //*------------------------------------------- handle the last 3 uint32_t's */
  224. case ALength of //* all the case statements fall through */
  225. 3: goto Case3;
  226. 2: goto Case2;
  227. 1: goto Case1;
  228. 0: goto Case0;
  229. end;
  230. Case3: c+=AKey[2];
  231. Case2: b+=AKey[1];
  232. Case1: a+=AKey[0];
  233. final_abc;
  234. Case0: //* case 0: nothing left to add */
  235. //*------------------------------------------------------ report the result */
  236. APrimaryHashAndInitVal := c;
  237. ASecondaryHashAndInitVal := b;
  238. end;
  239. function HashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): UInt32;
  240. var
  241. a, b, c: UInt32;
  242. u: record case byte of
  243. 0: (ptr: Pointer);
  244. 1: (i: PtrUint);
  245. end absolute AKey;
  246. k32: ^UInt32 absolute AKey;
  247. k16: ^UInt16 absolute AKey;
  248. k8: ^UInt8 absolute AKey;
  249. label _10, _8, _6, _4, _2;
  250. label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
  251. begin
  252. a := $DEADBEEF + UInt32(ALength) + AInitVal;
  253. b := a;
  254. c := b;
  255. {$IFDEF ENDIAN_LITTLE}
  256. if (u.i and $3) = 0 then
  257. begin
  258. while (ALength > 12) do
  259. begin
  260. a += k32[0];
  261. b += k32[1];
  262. c += k32[2];
  263. mix_abc;
  264. ALength -= 12;
  265. k32 += 3;
  266. end;
  267. case ALength of
  268. 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
  269. 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
  270. 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
  271. 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
  272. 8 : begin b += k32[1]; a += k32[0]; end;
  273. 7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
  274. 6 : begin b += k32[1] and $ffff; a += k32[0]; end;
  275. 5 : begin b += k32[1] and $ff; a += k32[0]; end;
  276. 4 : begin a += k32[0]; end;
  277. 3 : begin a += k32[0] and $ffffff; end;
  278. 2 : begin a += k32[0] and $ffff; end;
  279. 1 : begin a += k32[0] and $ff; end;
  280. 0 : Exit(c); // zero length strings require no mixing
  281. end
  282. end
  283. else
  284. if (u.i and $1) = 0 then
  285. begin
  286. while (ALength > 12) do
  287. begin
  288. a += k16[0] + (UInt32(k16[1]) shl 16);
  289. b += k16[2] + (UInt32(k16[3]) shl 16);
  290. c += k16[4] + (UInt32(k16[5]) shl 16);
  291. mix_abc;
  292. ALength -= 12;
  293. k16 += 6;
  294. end;
  295. case ALength of
  296. 12:
  297. begin
  298. c+=k16[4]+((UInt32(k16[5])) shl 16);
  299. b+=k16[2]+((UInt32(k16[3])) shl 16);
  300. a+=k16[0]+((UInt32(k16[1])) shl 16);
  301. end;
  302. 11:
  303. begin
  304. c+=(UInt32(k8[10])) shl 16; //* fall through */
  305. goto _10;
  306. end;
  307. 10:
  308. begin _10:
  309. c+=k16[4];
  310. b+=k16[2]+((UInt32(k16[3])) shl 16);
  311. a+=k16[0]+((UInt32(k16[1])) shl 16);
  312. end;
  313. 9 :
  314. begin
  315. c+=k8[8]; //* fall through */
  316. goto _8;
  317. end;
  318. 8 :
  319. begin _8:
  320. b+=k16[2]+((UInt32(k16[3])) shl 16);
  321. a+=k16[0]+((UInt32(k16[1])) shl 16);
  322. end;
  323. 7 :
  324. begin
  325. b+=(UInt32(k8[6])) shl 16; //* fall through */
  326. goto _6;
  327. end;
  328. 6 :
  329. begin _6:
  330. b+=k16[2];
  331. a+=k16[0]+((UInt32(k16[1])) shl 16);
  332. end;
  333. 5 :
  334. begin
  335. b+=k8[4]; //* fall through */
  336. goto _4;
  337. end;
  338. 4 :
  339. begin _4:
  340. a+=k16[0]+((UInt32(k16[1])) shl 16);
  341. end;
  342. 3 :
  343. begin
  344. a+=(UInt32(k8[2])) shl 16; //* fall through */
  345. goto _2;
  346. end;
  347. 2 :
  348. begin _2:
  349. a+=k16[0];
  350. end;
  351. 1 :
  352. begin
  353. a+=k8[0];
  354. end;
  355. 0 : Exit(c); //* zero length requires no mixing */
  356. end;
  357. end
  358. else
  359. {$ENDIF}
  360. begin
  361. while ALength > 12 do
  362. begin
  363. a += k8[0];
  364. a += (UInt32(k8[1])) shl 8;
  365. a += (UInt32(k8[2])) shl 16;
  366. a += (UInt32(k8[3])) shl 24;
  367. b += k8[4];
  368. b += (UInt32(k8[5])) shl 8;
  369. b += (UInt32(k8[6])) shl 16;
  370. b += (UInt32(k8[7])) shl 24;
  371. c += k8[8];
  372. c += (UInt32(k8[9])) shl 8;
  373. c += (UInt32(k8[10])) shl 16;
  374. c += (UInt32(k8[11])) shl 24;
  375. mix_abc;
  376. ALength -= 12;
  377. k8 += 12;
  378. end;
  379. case ALength of
  380. 12: goto Case12;
  381. 11: goto Case11;
  382. 10: goto Case10;
  383. 9 : goto Case9;
  384. 8 : goto Case8;
  385. 7 : goto Case7;
  386. 6 : goto Case6;
  387. 5 : goto Case5;
  388. 4 : goto Case4;
  389. 3 : goto Case3;
  390. 2 : goto Case2;
  391. 1 : goto Case1;
  392. 0 : Exit(c);
  393. end;
  394. Case12: c+=(UInt32(k8[11])) shl 24;
  395. Case11: c+=(UInt32(k8[10])) shl 16;
  396. Case10: c+=(UInt32(k8[9])) shl 8;
  397. Case9: c+=k8[8];
  398. Case8: b+=(UInt32(k8[7])) shl 24;
  399. Case7: b+=(UInt32(k8[6])) shl 16;
  400. Case6: b+=(UInt32(k8[5])) shl 8;
  401. Case5: b+=k8[4];
  402. Case4: a+=(UInt32(k8[3])) shl 24;
  403. Case3: a+=(UInt32(k8[2])) shl 16;
  404. Case2: a+=(UInt32(k8[1])) shl 8;
  405. Case1: a+=k8[0];
  406. end;
  407. final_abc;
  408. Result := c;
  409. end;
  410. (*
  411. * hashlittle2: return 2 32-bit hash values
  412. *
  413. * This is identical to hashlittle(), except it returns two 32-bit hash
  414. * values instead of just one. This is good enough for hash table
  415. * lookup with 2^^64 buckets, or if you want a second hash if you're not
  416. * happy with the first, or if you want a probably-unique 64-bit ID for
  417. * the key. *pc is better mixed than *pb, so use *pc first. If you want
  418. * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
  419. *)
  420. procedure HashLittle2(
  421. AKey: Pointer; //* the key to hash */
  422. ALength: SizeInt; //* length of the key */
  423. var APrimaryHashAndInitVal: UInt32; //* IN: primary initval, OUT: primary hash */
  424. var ASecondaryHashAndInitVal: UInt32); //* IN: secondary initval, OUT: secondary hash */
  425. var
  426. a,b,c: UInt32;
  427. u: record case byte of
  428. 0: (ptr: Pointer);
  429. 1: (i: PtrUint);
  430. end absolute AKey;
  431. k32: ^UInt32 absolute AKey;
  432. k16: ^UInt16 absolute AKey;
  433. k8: ^UInt8 absolute AKey;
  434. label _10, _8, _6, _4, _2;
  435. label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
  436. begin
  437. //* Set up the internal state */
  438. a := $DEADBEEF + UInt32(ALength) + APrimaryHashAndInitVal;
  439. b := a;
  440. c := b;
  441. c += ASecondaryHashAndInitVal;
  442. {$IFDEF ENDIAN_LITTLE}
  443. if (u.i and $3) = 0 then
  444. begin
  445. while (ALength > 12) do
  446. begin
  447. a += k32[0];
  448. b += k32[1];
  449. c += k32[2];
  450. mix_abc;
  451. ALength -= 12;
  452. k32 += 3;
  453. end;
  454. case ALength of
  455. 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
  456. 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
  457. 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
  458. 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
  459. 8 : begin b += k32[1]; a += k32[0]; end;
  460. 7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
  461. 6 : begin b += k32[1] and $ffff; a += k32[0]; end;
  462. 5 : begin b += k32[1] and $ff; a += k32[0]; end;
  463. 4 : begin a += k32[0]; end;
  464. 3 : begin a += k32[0] and $ffffff; end;
  465. 2 : begin a += k32[0] and $ffff; end;
  466. 1 : begin a += k32[0] and $ff; end;
  467. 0 :
  468. begin
  469. APrimaryHashAndInitVal := c;
  470. ASecondaryHashAndInitVal := b;
  471. Exit; // zero length strings require no mixing
  472. end;
  473. end
  474. end
  475. else
  476. if (u.i and $1) = 0 then
  477. begin
  478. while (ALength > 12) do
  479. begin
  480. a += k16[0] + (UInt32(k16[1]) shl 16);
  481. b += k16[2] + (UInt32(k16[3]) shl 16);
  482. c += k16[4] + (UInt32(k16[5]) shl 16);
  483. mix_abc;
  484. ALength -= 12;
  485. k16 += 6;
  486. end;
  487. case ALength of
  488. 12:
  489. begin
  490. c+=k16[4]+((UInt32(k16[5])) shl 16);
  491. b+=k16[2]+((UInt32(k16[3])) shl 16);
  492. a+=k16[0]+((UInt32(k16[1])) shl 16);
  493. end;
  494. 11:
  495. begin
  496. c+=(UInt32(k8[10])) shl 16; //* fall through */
  497. goto _10;
  498. end;
  499. 10:
  500. begin _10:
  501. c+=k16[4];
  502. b+=k16[2]+((UInt32(k16[3])) shl 16);
  503. a+=k16[0]+((UInt32(k16[1])) shl 16);
  504. end;
  505. 9 :
  506. begin
  507. c+=k8[8]; //* fall through */
  508. goto _8;
  509. end;
  510. 8 :
  511. begin _8:
  512. b+=k16[2]+((UInt32(k16[3])) shl 16);
  513. a+=k16[0]+((UInt32(k16[1])) shl 16);
  514. end;
  515. 7 :
  516. begin
  517. b+=(UInt32(k8[6])) shl 16; //* fall through */
  518. goto _6;
  519. end;
  520. 6 :
  521. begin _6:
  522. b+=k16[2];
  523. a+=k16[0]+((UInt32(k16[1])) shl 16);
  524. end;
  525. 5 :
  526. begin
  527. b+=k8[4]; //* fall through */
  528. goto _4;
  529. end;
  530. 4 :
  531. begin _4:
  532. a+=k16[0]+((UInt32(k16[1])) shl 16);
  533. end;
  534. 3 :
  535. begin
  536. a+=(UInt32(k8[2])) shl 16; //* fall through */
  537. goto _2;
  538. end;
  539. 2 :
  540. begin _2:
  541. a+=k16[0];
  542. end;
  543. 1 :
  544. begin
  545. a+=k8[0];
  546. end;
  547. 0 :
  548. begin
  549. APrimaryHashAndInitVal := c;
  550. ASecondaryHashAndInitVal := b;
  551. Exit; // zero length strings require no mixing
  552. end;
  553. end;
  554. end
  555. else
  556. {$ENDIF}
  557. begin
  558. while ALength > 12 do
  559. begin
  560. a += k8[0];
  561. a += (UInt32(k8[1])) shl 8;
  562. a += (UInt32(k8[2])) shl 16;
  563. a += (UInt32(k8[3])) shl 24;
  564. b += k8[4];
  565. b += (UInt32(k8[5])) shl 8;
  566. b += (UInt32(k8[6])) shl 16;
  567. b += (UInt32(k8[7])) shl 24;
  568. c += k8[8];
  569. c += (UInt32(k8[9])) shl 8;
  570. c += (UInt32(k8[10])) shl 16;
  571. c += (UInt32(k8[11])) shl 24;
  572. mix_abc;
  573. ALength -= 12;
  574. k8 += 12;
  575. end;
  576. case ALength of
  577. 12: goto Case12;
  578. 11: goto Case11;
  579. 10: goto Case10;
  580. 9 : goto Case9;
  581. 8 : goto Case8;
  582. 7 : goto Case7;
  583. 6 : goto Case6;
  584. 5 : goto Case5;
  585. 4 : goto Case4;
  586. 3 : goto Case3;
  587. 2 : goto Case2;
  588. 1 : goto Case1;
  589. 0 :
  590. begin
  591. APrimaryHashAndInitVal := c;
  592. ASecondaryHashAndInitVal := b;
  593. Exit; // zero length strings require no mixing
  594. end;
  595. end;
  596. Case12: c+=(UInt32(k8[11])) shl 24;
  597. Case11: c+=(UInt32(k8[10])) shl 16;
  598. Case10: c+=(UInt32(k8[9])) shl 8;
  599. Case9: c+=k8[8];
  600. Case8: b+=(UInt32(k8[7])) shl 24;
  601. Case7: b+=(UInt32(k8[6])) shl 16;
  602. Case6: b+=(UInt32(k8[5])) shl 8;
  603. Case5: b+=k8[4];
  604. Case4: a+=(UInt32(k8[3])) shl 24;
  605. Case3: a+=(UInt32(k8[2])) shl 16;
  606. Case2: a+=(UInt32(k8[1])) shl 8;
  607. Case1: a+=k8[0];
  608. end;
  609. final_abc;
  610. APrimaryHashAndInitVal := c;
  611. ASecondaryHashAndInitVal := b;
  612. end;
  613. procedure DelphiHashLittle2(AKey: Pointer; ALength: SizeInt; var APrimaryHashAndInitVal, ASecondaryHashAndInitVal: UInt32);
  614. var
  615. a,b,c: UInt32;
  616. u: record case byte of
  617. 0: (ptr: Pointer);
  618. 1: (i: PtrUint);
  619. end absolute AKey;
  620. k32: ^UInt32 absolute AKey;
  621. k16: ^UInt16 absolute AKey;
  622. k8: ^UInt8 absolute AKey;
  623. label _10, _8, _6, _4, _2;
  624. label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
  625. begin
  626. //* Set up the internal state */
  627. a := $DEADBEEF + UInt32(ALength shl 2) + APrimaryHashAndInitVal; // delphi version bug? original version don't have "shl 2"
  628. b := a;
  629. c := b;
  630. c += ASecondaryHashAndInitVal;
  631. {$IFDEF ENDIAN_LITTLE}
  632. if (u.i and $3) = 0 then
  633. begin
  634. while (ALength > 12) do
  635. begin
  636. a += k32[0];
  637. b += k32[1];
  638. c += k32[2];
  639. mix_abc;
  640. ALength -= 12;
  641. k32 += 3;
  642. end;
  643. case ALength of
  644. 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
  645. 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
  646. 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
  647. 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
  648. 8 : begin b += k32[1]; a += k32[0]; end;
  649. 7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
  650. 6 : begin b += k32[1] and $ffff; a += k32[0]; end;
  651. 5 : begin b += k32[1] and $ff; a += k32[0]; end;
  652. 4 : begin a += k32[0]; end;
  653. 3 : begin a += k32[0] and $ffffff; end;
  654. 2 : begin a += k32[0] and $ffff; end;
  655. 1 : begin a += k32[0] and $ff; end;
  656. 0 :
  657. begin
  658. APrimaryHashAndInitVal := c;
  659. ASecondaryHashAndInitVal := b;
  660. Exit; // zero length strings require no mixing
  661. end;
  662. end
  663. end
  664. else
  665. if (u.i and $1) = 0 then
  666. begin
  667. while (ALength > 12) do
  668. begin
  669. a += k16[0] + (UInt32(k16[1]) shl 16);
  670. b += k16[2] + (UInt32(k16[3]) shl 16);
  671. c += k16[4] + (UInt32(k16[5]) shl 16);
  672. mix_abc;
  673. ALength -= 12;
  674. k16 += 6;
  675. end;
  676. case ALength of
  677. 12:
  678. begin
  679. c+=k16[4]+((UInt32(k16[5])) shl 16);
  680. b+=k16[2]+((UInt32(k16[3])) shl 16);
  681. a+=k16[0]+((UInt32(k16[1])) shl 16);
  682. end;
  683. 11:
  684. begin
  685. c+=(UInt32(k8[10])) shl 16; //* fall through */
  686. goto _10;
  687. end;
  688. 10:
  689. begin _10:
  690. c+=k16[4];
  691. b+=k16[2]+((UInt32(k16[3])) shl 16);
  692. a+=k16[0]+((UInt32(k16[1])) shl 16);
  693. end;
  694. 9 :
  695. begin
  696. c+=k8[8]; //* fall through */
  697. goto _8;
  698. end;
  699. 8 :
  700. begin _8:
  701. b+=k16[2]+((UInt32(k16[3])) shl 16);
  702. a+=k16[0]+((UInt32(k16[1])) shl 16);
  703. end;
  704. 7 :
  705. begin
  706. b+=(UInt32(k8[6])) shl 16; //* fall through */
  707. goto _6;
  708. end;
  709. 6 :
  710. begin _6:
  711. b+=k16[2];
  712. a+=k16[0]+((UInt32(k16[1])) shl 16);
  713. end;
  714. 5 :
  715. begin
  716. b+=k8[4]; //* fall through */
  717. goto _4;
  718. end;
  719. 4 :
  720. begin _4:
  721. a+=k16[0]+((UInt32(k16[1])) shl 16);
  722. end;
  723. 3 :
  724. begin
  725. a+=(UInt32(k8[2])) shl 16; //* fall through */
  726. goto _2;
  727. end;
  728. 2 :
  729. begin _2:
  730. a+=k16[0];
  731. end;
  732. 1 :
  733. begin
  734. a+=k8[0];
  735. end;
  736. 0 :
  737. begin
  738. APrimaryHashAndInitVal := c;
  739. ASecondaryHashAndInitVal := b;
  740. Exit; // zero length strings require no mixing
  741. end;
  742. end;
  743. end
  744. else
  745. {$ENDIF}
  746. begin
  747. while ALength > 12 do
  748. begin
  749. a += k8[0];
  750. a += (UInt32(k8[1])) shl 8;
  751. a += (UInt32(k8[2])) shl 16;
  752. a += (UInt32(k8[3])) shl 24;
  753. b += k8[4];
  754. b += (UInt32(k8[5])) shl 8;
  755. b += (UInt32(k8[6])) shl 16;
  756. b += (UInt32(k8[7])) shl 24;
  757. c += k8[8];
  758. c += (UInt32(k8[9])) shl 8;
  759. c += (UInt32(k8[10])) shl 16;
  760. c += (UInt32(k8[11])) shl 24;
  761. mix_abc;
  762. ALength -= 12;
  763. k8 += 12;
  764. end;
  765. case ALength of
  766. 12: goto Case12;
  767. 11: goto Case11;
  768. 10: goto Case10;
  769. 9 : goto Case9;
  770. 8 : goto Case8;
  771. 7 : goto Case7;
  772. 6 : goto Case6;
  773. 5 : goto Case5;
  774. 4 : goto Case4;
  775. 3 : goto Case3;
  776. 2 : goto Case2;
  777. 1 : goto Case1;
  778. 0 :
  779. begin
  780. APrimaryHashAndInitVal := c;
  781. ASecondaryHashAndInitVal := b;
  782. Exit; // zero length strings require no mixing
  783. end;
  784. end;
  785. Case12: c+=(UInt32(k8[11])) shl 24;
  786. Case11: c+=(UInt32(k8[10])) shl 16;
  787. Case10: c+=(UInt32(k8[9])) shl 8;
  788. Case9: c+=k8[8];
  789. Case8: b+=(UInt32(k8[7])) shl 24;
  790. Case7: b+=(UInt32(k8[6])) shl 16;
  791. Case6: b+=(UInt32(k8[5])) shl 8;
  792. Case5: b+=k8[4];
  793. Case4: a+=(UInt32(k8[3])) shl 24;
  794. Case3: a+=(UInt32(k8[2])) shl 16;
  795. Case2: a+=(UInt32(k8[1])) shl 8;
  796. Case1: a+=k8[0];
  797. end;
  798. final_abc;
  799. APrimaryHashAndInitVal := c;
  800. ASecondaryHashAndInitVal := b;
  801. end;
  802. function DelphiHashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): Int32;
  803. var
  804. a, b, c: UInt32;
  805. u: record case byte of
  806. 0: (ptr: Pointer);
  807. 1: (i: PtrUint);
  808. end absolute AKey;
  809. k32: ^UInt32 absolute AKey;
  810. //k16: ^UInt16 absolute AKey;
  811. k8: ^UInt8 absolute AKey;
  812. label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
  813. begin
  814. a := $DEADBEEF + UInt32(ALength shl 2) + AInitVal; // delphi version bug? original version don't have "shl 2"
  815. b := a;
  816. c := b;
  817. {.$IFDEF ENDIAN_LITTLE} // Delphi version don't care
  818. if (u.i and $3) = 0 then
  819. begin
  820. while (ALength > 12) do
  821. begin
  822. a += k32[0];
  823. b += k32[1];
  824. c += k32[2];
  825. mix_abc;
  826. ALength -= 12;
  827. k32 += 3;
  828. end;
  829. case ALength of
  830. 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
  831. 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
  832. 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
  833. 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
  834. 8 : begin b += k32[1]; a += k32[0]; end;
  835. 7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
  836. 6 : begin b += k32[1] and $ffff; a += k32[0]; end;
  837. 5 : begin b += k32[1] and $ff; a += k32[0]; end;
  838. 4 : begin a += k32[0]; end;
  839. 3 : begin a += k32[0] and $ffffff; end;
  840. 2 : begin a += k32[0] and $ffff; end;
  841. 1 : begin a += k32[0] and $ff; end;
  842. 0 : Exit(c); // zero length strings require no mixing
  843. end
  844. end
  845. else
  846. {.$ENDIF}
  847. begin
  848. while ALength > 12 do
  849. begin
  850. a += k8[0];
  851. a += (UInt32(k8[1])) shl 8;
  852. a += (UInt32(k8[2])) shl 16;
  853. a += (UInt32(k8[3])) shl 24;
  854. b += k8[4];
  855. b += (UInt32(k8[5])) shl 8;
  856. b += (UInt32(k8[6])) shl 16;
  857. b += (UInt32(k8[7])) shl 24;
  858. c += k8[8];
  859. c += (UInt32(k8[9])) shl 8;
  860. c += (UInt32(k8[10])) shl 16;
  861. c += (UInt32(k8[11])) shl 24;
  862. mix_abc;
  863. ALength -= 12;
  864. k8 += 12;
  865. end;
  866. case ALength of
  867. 12: goto Case12;
  868. 11: goto Case11;
  869. 10: goto Case10;
  870. 9 : goto Case9;
  871. 8 : goto Case8;
  872. 7 : goto Case7;
  873. 6 : goto Case6;
  874. 5 : goto Case5;
  875. 4 : goto Case4;
  876. 3 : goto Case3;
  877. 2 : goto Case2;
  878. 1 : goto Case1;
  879. 0 : Exit(c);
  880. end;
  881. Case12: c+=(UInt32(k8[11])) shl 24;
  882. Case11: c+=(UInt32(k8[10])) shl 16;
  883. Case10: c+=(UInt32(k8[9])) shl 8;
  884. Case9: c+=k8[8];
  885. Case8: b+=(UInt32(k8[7])) shl 24;
  886. Case7: b+=(UInt32(k8[6])) shl 16;
  887. Case6: b+=(UInt32(k8[5])) shl 8;
  888. Case5: b+=k8[4];
  889. Case4: a+=(UInt32(k8[3])) shl 24;
  890. Case3: a+=(UInt32(k8[2])) shl 16;
  891. Case2: a+=(UInt32(k8[1])) shl 8;
  892. Case1: a+=k8[0];
  893. end;
  894. final_abc;
  895. Result := Int32(c);
  896. end;
  897. {$ifdef CPUARM} // circumvent FPC issue on ARM
  898. function ToByte(value: cardinal): cardinal; inline;
  899. begin
  900. result := value and $ff;
  901. end;
  902. {$else}
  903. type ToByte = byte;
  904. {$endif}
  905. {$ifdef CPUINTEL} // use optimized x86/x64 asm versions for xxHash32
  906. {$ifdef CPUX86}
  907. function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal;
  908. asm
  909. xchg edx, ecx
  910. push ebp
  911. push edi
  912. lea ebp, [ecx+edx]
  913. push esi
  914. push ebx
  915. sub esp, 8
  916. cmp edx, 15
  917. mov ebx, eax
  918. mov dword ptr [esp], edx
  919. lea eax, [ebx+165667B1H]
  920. jbe @2
  921. lea eax, [ebp-10H]
  922. lea edi, [ebx+24234428H]
  923. lea esi, [ebx-7A143589H]
  924. mov dword ptr [esp+4H], ebp
  925. mov edx, eax
  926. lea eax, [ebx+61C8864FH]
  927. mov ebp, edx
  928. @1: mov edx, dword ptr [ecx]
  929. imul edx, edx, -2048144777
  930. add edi, edx
  931. rol edi, 13
  932. imul edi, edi, -1640531535
  933. mov edx, dword ptr [ecx+4]
  934. imul edx, edx, -2048144777
  935. add esi, edx
  936. rol esi, 13
  937. imul esi, esi, -1640531535
  938. mov edx, dword ptr [ecx+8]
  939. imul edx, edx, -2048144777
  940. add ebx, edx
  941. rol ebx, 13
  942. imul ebx, ebx, -1640531535
  943. mov edx, dword ptr [ecx+12]
  944. lea ecx, [ecx+16]
  945. imul edx, edx, -2048144777
  946. add eax, edx
  947. rol eax, 13
  948. imul eax, eax, -1640531535
  949. cmp ebp, ecx
  950. jnc @1
  951. rol edi, 1
  952. rol esi, 7
  953. rol ebx, 12
  954. add esi, edi
  955. mov ebp, dword ptr [esp+4H]
  956. ror eax, 14
  957. add ebx, esi
  958. add eax, ebx
  959. @2: lea esi, [ecx+4H]
  960. add eax, dword ptr [esp]
  961. cmp ebp, esi
  962. jc @4
  963. mov ebx, esi
  964. nop
  965. @3: imul edx, dword ptr [ebx-4H], -1028477379
  966. add ebx, 4
  967. add eax, edx
  968. ror eax, 15
  969. imul eax, eax, 668265263
  970. cmp ebp, ebx
  971. jnc @3
  972. lea edx, [ebp-4H]
  973. sub edx, ecx
  974. mov ecx, edx
  975. and ecx, 0FFFFFFFCH
  976. add ecx, esi
  977. @4: cmp ebp, ecx
  978. jbe @6
  979. @5: movzx edx, byte ptr [ecx]
  980. add ecx, 1
  981. imul edx, edx, 374761393
  982. add eax, edx
  983. rol eax, 11
  984. imul eax, eax, -1640531535
  985. cmp ebp, ecx
  986. jnz @5
  987. nop
  988. @6: mov edx, eax
  989. add esp, 8
  990. shr edx, 15
  991. xor eax, edx
  992. imul eax, eax, -2048144777
  993. pop ebx
  994. pop esi
  995. mov edx, eax
  996. shr edx, 13
  997. xor eax, edx
  998. imul eax, eax, -1028477379
  999. pop edi
  1000. pop ebp
  1001. mov edx, eax
  1002. shr edx, 16
  1003. xor eax, edx
  1004. end;
  1005. {$endif CPUX86}
  1006. {$ifdef CPUX64}
  1007. function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal;
  1008. asm
  1009. {$ifndef WIN64} // crc=rdi P=rsi len=rdx
  1010. mov r8, rdi
  1011. mov rcx, rsi
  1012. {$else} // crc=r8 P=rcx len=rdx
  1013. mov r10, r8
  1014. mov r8, rcx
  1015. mov rcx, rdx
  1016. mov rdx, r10
  1017. push rsi // Win64 expects those registers to be preserved
  1018. push rdi
  1019. {$endif}
  1020. // P=r8 len=rcx crc=rdx
  1021. push rbx
  1022. lea r10, [rcx+rdx]
  1023. cmp rdx, 15
  1024. lea eax, [r8+165667B1H]
  1025. jbe @2
  1026. lea rsi, [r10-10H]
  1027. lea ebx, [r8+24234428H]
  1028. lea edi, [r8-7A143589H]
  1029. lea eax, [r8+61C8864FH]
  1030. @1: imul r9d, dword ptr [rcx], -2048144777
  1031. add rcx, 16
  1032. imul r11d, dword ptr [rcx-0CH], -2048144777
  1033. add ebx, r9d
  1034. lea r9d, [r11+rdi]
  1035. rol ebx, 13
  1036. rol r9d, 13
  1037. imul ebx, ebx, -1640531535
  1038. imul edi, r9d, -1640531535
  1039. imul r9d, dword ptr [rcx-8H], -2048144777
  1040. add r8d, r9d
  1041. imul r9d, dword ptr [rcx-4H], -2048144777
  1042. rol r8d, 13
  1043. imul r8d, r8d, -1640531535
  1044. add eax, r9d
  1045. rol eax, 13
  1046. imul eax, eax, -1640531535
  1047. cmp rsi, rcx
  1048. jnc @1
  1049. rol edi, 7
  1050. rol ebx, 1
  1051. rol r8d, 12
  1052. mov r9d, edi
  1053. ror eax, 14
  1054. add r9d, ebx
  1055. add r8d, r9d
  1056. add eax, r8d
  1057. @2: lea r9, [rcx+4H]
  1058. add eax, edx
  1059. cmp r10, r9
  1060. jc @4
  1061. mov r8, r9
  1062. @3: imul edx, dword ptr [r8-4H], -1028477379
  1063. add r8, 4
  1064. add eax, edx
  1065. ror eax, 15
  1066. imul eax, eax, 668265263
  1067. cmp r10, r8
  1068. jnc @3
  1069. lea rdx, [r10-4H]
  1070. sub rdx, rcx
  1071. mov rcx, rdx
  1072. and rcx, 0FFFFFFFFFFFFFFFCH
  1073. add rcx, r9
  1074. @4: cmp r10, rcx
  1075. jbe @6
  1076. @5: movzx edx, byte ptr [rcx]
  1077. add rcx, 1
  1078. imul edx, edx, 374761393
  1079. add eax, edx
  1080. rol eax, 11
  1081. imul eax, eax, -1640531535
  1082. cmp r10, rcx
  1083. jnz @5
  1084. @6: mov edx, eax
  1085. shr edx, 15
  1086. xor eax, edx
  1087. imul eax, eax, -2048144777
  1088. mov edx, eax
  1089. shr edx, 13
  1090. xor eax, edx
  1091. imul eax, eax, -1028477379
  1092. mov edx, eax
  1093. shr edx, 16
  1094. xor eax, edx
  1095. pop rbx
  1096. {$ifdef WIN64}
  1097. pop rdi
  1098. pop rsi
  1099. {$endif}
  1100. end;
  1101. {$endif CPUX64}
  1102. {$else not CPUINTEL}
  1103. function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal;
  1104. begin
  1105. result := xxHash32Pascal(crc, P, len);
  1106. end;
  1107. {$endif CPUINTEL}
  1108. const
  1109. PRIME32_1 = 2654435761;
  1110. PRIME32_2 = 2246822519;
  1111. PRIME32_3 = 3266489917;
  1112. PRIME32_4 = 668265263;
  1113. PRIME32_5 = 374761393;
  1114. // RolDWord is an intrinsic function under FPC :)
  1115. function Rol13(value: cardinal): cardinal; inline;
  1116. begin
  1117. result := RolDWord(value, 13);
  1118. end;
  1119. function xxHash32Pascal(crc: cardinal; P: Pointer; len: integer): cardinal;
  1120. var c1, c2, c3, c4: cardinal;
  1121. PLimit, PEnd: PAnsiChar;
  1122. begin
  1123. PEnd := P + len;
  1124. if len >= 16 then begin
  1125. PLimit := PEnd - 16;
  1126. c3 := crc;
  1127. c2 := c3 + PRIME32_2;
  1128. c1 := c2 + PRIME32_1;
  1129. c4 := c3 - PRIME32_1;
  1130. repeat
  1131. c1 := PRIME32_1 * Rol13(c1 + PRIME32_2 * PCardinal(P)^);
  1132. c2 := PRIME32_1 * Rol13(c2 + PRIME32_2 * PCardinal(P+4)^);
  1133. c3 := PRIME32_1 * Rol13(c3 + PRIME32_2 * PCardinal(P+8)^);
  1134. c4 := PRIME32_1 * Rol13(c4 + PRIME32_2 * PCardinal(P+12)^);
  1135. inc(P, 16);
  1136. until not (P <= PLimit);
  1137. result := RolDWord(c1, 1) + RolDWord(c2, 7) + RolDWord(c3, 12) + RolDWord(c4, 18);
  1138. end else
  1139. result := crc + PRIME32_5;
  1140. inc(result, len);
  1141. { Use "P + 4 <= PEnd" instead of "P <= PEnd - 4" to avoid crashes in case P = nil.
  1142. When P = nil,
  1143. then "PtrUInt(PEnd - 4)" is 4294967292,
  1144. so the condition "P <= PEnd - 4" would be satisfied,
  1145. and the code would try to access PCardinal(nil)^ causing a SEGFAULT. }
  1146. while P + 4 <= PEnd do begin
  1147. inc(result, PCardinal(P)^ * PRIME32_3);
  1148. result := RolDWord(result, 17) * PRIME32_4;
  1149. inc(P, 4);
  1150. end;
  1151. while P < PEnd do begin
  1152. inc(result, PByte(P)^ * PRIME32_5);
  1153. result := RolDWord(result, 11) * PRIME32_1;
  1154. inc(P);
  1155. end;
  1156. result := result xor (result shr 15);
  1157. result := result * PRIME32_2;
  1158. result := result xor (result shr 13);
  1159. result := result * PRIME32_3;
  1160. result := result xor (result shr 16);
  1161. end;
  1162. {$ifdef CPUINTEL}
  1163. {$ifdef CPU64}
  1164. function crc32csse42(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal; nostackframe; assembler;
  1165. asm
  1166. mov eax, crc
  1167. test len, len
  1168. jz @z
  1169. test buf, buf
  1170. jz @z
  1171. not eax
  1172. mov ecx, len
  1173. shr len, 3
  1174. jnz @by8 // we don't care for read alignment
  1175. @0: test cl, 4
  1176. jz @4
  1177. crc32 eax, dword ptr [buf]
  1178. add buf, 4
  1179. @4: test cl, 2
  1180. jz @2
  1181. crc32 eax, word ptr [buf]
  1182. add buf, 2
  1183. @2: test cl, 1
  1184. jz @1
  1185. crc32 eax, byte ptr [buf]
  1186. @1: not eax
  1187. @z: ret
  1188. align 16
  1189. @by8: crc32 rax, qword ptr [buf] // hash 8 bytes per loop
  1190. add buf, 8
  1191. sub len, 1
  1192. jnz @by8
  1193. jmp @0
  1194. end;
  1195. {$else}
  1196. function crc32csse42(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal; nostackframe; assembler;
  1197. asm
  1198. // eax=crc, edx=buf, ecx=len
  1199. not eax
  1200. test ecx, ecx
  1201. jz @0
  1202. test edx, edx
  1203. jz @0
  1204. jmp @align
  1205. @a: crc32 eax, byte ptr [edx]
  1206. inc edx
  1207. dec ecx
  1208. jz @0
  1209. @align: test dl, 3
  1210. jnz @a
  1211. push ecx
  1212. shr ecx, 3
  1213. jnz @by8
  1214. @rem: pop ecx
  1215. test cl, 4
  1216. jz @4
  1217. crc32 eax, dword ptr [edx]
  1218. add edx, 4
  1219. @4: test cl, 2
  1220. jz @2
  1221. crc32 eax, word ptr [edx]
  1222. add edx, 2
  1223. @2: test cl, 1
  1224. jz @0
  1225. crc32 eax, byte ptr [edx]
  1226. @0: not eax
  1227. ret
  1228. @by8: crc32 eax, dword ptr [edx]
  1229. crc32 eax, dword ptr [edx + 4]
  1230. add edx, 8
  1231. dec ecx
  1232. jnz @by8
  1233. jmp @rem
  1234. end;
  1235. {$endif}
  1236. {$endif CPUINTEL}
  1237. var
  1238. crc32ctab: array[0..{$ifdef PUREPASCAL}3{$else}7{$endif},byte] of cardinal;
  1239. function crc32cfast(crc: cardinal; buf: Pointer; len: cardinal): cardinal;
  1240. {$ifdef PUREPASCAL}
  1241. begin
  1242. result := not crc;
  1243. if (buf<>nil) and (len>0) then begin
  1244. repeat
  1245. if PtrUInt(buf) and 3=0 then // align to 4 bytes boundary
  1246. break;
  1247. result := crc32ctab[0,ToByte(result xor cardinal(buf^))] xor (result shr 8);
  1248. dec(len);
  1249. inc(buf);
  1250. until len=0;
  1251. while len>=4 do begin
  1252. result := result xor PCardinal(buf)^;
  1253. inc(buf,4);
  1254. result := crc32ctab[3,ToByte(result)] xor
  1255. crc32ctab[2,ToByte(result shr 8)] xor
  1256. crc32ctab[1,ToByte(result shr 16)] xor
  1257. crc32ctab[0,result shr 24];
  1258. dec(len,4);
  1259. end;
  1260. while len>0 do begin
  1261. result := crc32ctab[0,ToByte(result xor cardinal(buf^))] xor (result shr 8);
  1262. dec(len);
  1263. inc(buf);
  1264. end;
  1265. end;
  1266. result := not result;
  1267. end;
  1268. {$else}
  1269. // adapted from fast Aleksandr Sharahov version
  1270. asm
  1271. test edx, edx
  1272. jz @ret
  1273. neg ecx
  1274. jz @ret
  1275. not eax
  1276. push ebx
  1277. @head: test dl, 3
  1278. jz @aligned
  1279. movzx ebx, byte[edx]
  1280. inc edx
  1281. xor bl, al
  1282. shr eax, 8
  1283. xor eax, dword ptr[ebx * 4 + crc32ctab]
  1284. inc ecx
  1285. jnz @head
  1286. pop ebx
  1287. not eax
  1288. ret
  1289. @ret: rep ret
  1290. @aligned:
  1291. sub edx, ecx
  1292. add ecx, 8
  1293. jg @bodydone
  1294. push esi
  1295. push edi
  1296. mov edi, edx
  1297. mov edx, eax
  1298. @bodyloop:
  1299. mov ebx, [edi + ecx - 4]
  1300. xor edx, [edi + ecx - 8]
  1301. movzx esi, bl
  1302. mov eax, dword ptr[esi * 4 + crc32ctab + 1024 * 3]
  1303. movzx esi, bh
  1304. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 2]
  1305. shr ebx, 16
  1306. movzx esi, bl
  1307. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 1]
  1308. movzx esi, bh
  1309. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 0]
  1310. movzx esi, dl
  1311. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 7]
  1312. movzx esi, dh
  1313. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 6]
  1314. shr edx, 16
  1315. movzx esi, dl
  1316. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 5]
  1317. movzx esi, dh
  1318. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 4]
  1319. add ecx, 8
  1320. jg @done
  1321. mov ebx, [edi + ecx - 4]
  1322. xor eax, [edi + ecx - 8]
  1323. movzx esi, bl
  1324. mov edx, dword ptr[esi * 4 + crc32ctab + 1024 * 3]
  1325. movzx esi, bh
  1326. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 2]
  1327. shr ebx, 16
  1328. movzx esi, bl
  1329. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 1]
  1330. movzx esi, bh
  1331. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 0]
  1332. movzx esi, al
  1333. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 7]
  1334. movzx esi, ah
  1335. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 6]
  1336. shr eax, 16
  1337. movzx esi, al
  1338. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 5]
  1339. movzx esi, ah
  1340. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 4]
  1341. add ecx, 8
  1342. jle @bodyloop
  1343. mov eax, edx
  1344. @done: mov edx, edi
  1345. pop edi
  1346. pop esi
  1347. @bodydone:
  1348. sub ecx, 8
  1349. jl @tail
  1350. pop ebx
  1351. not eax
  1352. ret
  1353. @tail: movzx ebx, byte[edx + ecx]
  1354. xor bl, al
  1355. shr eax, 8
  1356. xor eax, dword ptr[ebx * 4 + crc32ctab]
  1357. inc ecx
  1358. jnz @tail
  1359. pop ebx
  1360. not eax
  1361. end;
  1362. {$endif PUREPASCAL}
  1363. procedure InitializeCrc32ctab;
  1364. var
  1365. i, n: integer;
  1366. crc: cardinal;
  1367. begin
  1368. // initialize tables for crc32cfast() and SymmetricEncrypt/FillRandom
  1369. for i := 0 to 255 do begin
  1370. crc := i;
  1371. for n := 1 to 8 do
  1372. if (crc and 1)<>0 then // polynom is not the same as with zlib's crc32()
  1373. crc := (crc shr 1) xor $82f63b78 else
  1374. crc := crc shr 1;
  1375. crc32ctab[0,i] := crc;
  1376. end;
  1377. for i := 0 to 255 do begin
  1378. crc := crc32ctab[0,i];
  1379. for n := 1 to high(crc32ctab) do begin
  1380. crc := (crc shr 8) xor crc32ctab[0,ToByte(crc)];
  1381. crc32ctab[n,i] := crc;
  1382. end;
  1383. end;
  1384. end;
  1385. begin
  1386. {$ifdef CPUINTEL}
  1387. if SSE42Support then
  1388. begin
  1389. crc32c := @crc32csse42;
  1390. mORMotHasher := @crc32csse42;
  1391. end
  1392. else
  1393. {$endif CPUINTEL}
  1394. begin
  1395. InitializeCrc32ctab;
  1396. crc32c := @crc32cfast;
  1397. mORMotHasher := @{$IFDEF CPUINTEL}xxHash32{$ELSE}xxHash32Pascal{$ENDIF};
  1398. end;
  1399. end.