generics.hashes.pas 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957
  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. {$IFNDEF FPC_DOTTEDUNITS}
  19. unit Generics.Hashes;
  20. {$ENDIF}
  21. {$MODE DELPHI}{$H+}
  22. {$POINTERMATH ON}
  23. {$MACRO ON}
  24. {$COPERATORS ON}
  25. {$OVERFLOWCHECKS OFF}
  26. {$RANGECHECKS OFF}
  27. {$IFDEF CPUWASM}
  28. {$DEFINE NOGOTO}
  29. {$ENDIF}
  30. interface
  31. uses
  32. {$IFDEF FPC_DOTTEDUNITS}
  33. System.Classes, System.SysUtils;
  34. {$ELSE FPC_DOTTEDUNITS}
  35. Classes, SysUtils;
  36. {$ENDIF FPC_DOTTEDUNITS}
  37. { Warning: the following set of macro code
  38. that decides to use assembler or normal code
  39. needs to stay after the _INTERFACE keyword
  40. because FPC_PIC macro is only set after this keyword,
  41. as it can be modified before by the global $PIC preprocessor directive.
  42. Pierre Muller 2018/07/04 }
  43. {$ifdef FPC_PIC}
  44. {$define DISABLE_X86_CPUINTEL}
  45. {$endif FPC_PIC}
  46. {$if defined(OPENBSD) or defined(EMX) or defined(OS2)}
  47. { These targets have old GNU assemblers that }
  48. { do not support all instructions used in assembler code below }
  49. {$define DISABLE_X86_CPUINTEL}
  50. {$endif}
  51. {$ifdef CPU64}
  52. {$define PUREPASCAL}
  53. {$ifdef CPUX64}
  54. {$define CPUINTEL}
  55. {$ASMMODE INTEL}
  56. {$endif CPUX64}
  57. {$else}
  58. {$ifdef CPUX86}
  59. {$ifndef DISABLE_X86_CPUINTEL}
  60. {$define CPUINTEL}
  61. {$ASMMODE INTEL}
  62. {$else}
  63. { Assembler code uses references to static
  64. variables with are not PIC ready }
  65. {$define PUREPASCAL}
  66. {$endif}
  67. {$else CPUX86}
  68. {$define PUREPASCAL}
  69. {$endif}
  70. {$endif CPU64}
  71. // Original version of Bob Jenkins Hash
  72. // http://burtleburtle.net/bob/c/lookup3.c
  73. function HashWord(
  74. AKey: PLongWord; //* the key, an array of uint32_t values */
  75. ALength: SizeInt; //* the length of the key, in uint32_ts */
  76. AInitVal: UInt32): UInt32; //* the previous hash, or an arbitrary value */
  77. procedure HashWord2 (
  78. AKey: PLongWord; //* the key, an array of uint32_t values */
  79. ALength: SizeInt; //* the length of the key, in uint32_ts */
  80. var APrimaryHashAndInitVal: UInt32; //* IN: seed OUT: primary hash value */
  81. var ASecondaryHashAndInitVal: UInt32); //* IN: more seed OUT: secondary hash value */
  82. function HashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): UInt32;
  83. procedure HashLittle2(
  84. AKey: Pointer; //* the key to hash */
  85. ALength: SizeInt; //* length of the key */
  86. var APrimaryHashAndInitVal: UInt32; //* IN: primary initval, OUT: primary hash */
  87. var ASecondaryHashAndInitVal: UInt32); //* IN: secondary initval, OUT: secondary hash */
  88. function DelphiHashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): Int32;
  89. procedure DelphiHashLittle2(AKey: Pointer; ALength: SizeInt; var APrimaryHashAndInitVal, ASecondaryHashAndInitVal: UInt32);
  90. // hash function from fstl
  91. function SimpleChecksumHash(AKey: Pointer; ALength: SizeInt): UInt32;
  92. // some other hashes
  93. // http://stackoverflow.com/questions/14409466/simple-hash-functions
  94. // http://www.partow.net/programming/hashfunctions/
  95. // http://en.wikipedia.org/wiki/List_of_hash_functions
  96. // http://www.cse.yorku.ca/~oz/hash.html
  97. // https://code.google.com/p/hedgewars/source/browse/hedgewars/adler32.pas
  98. function Adler32(AKey: Pointer; ALength: SizeInt): UInt32;
  99. function sdbm(AKey: Pointer; ALength: SizeInt): UInt32;
  100. function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal;{$IFNDEF CPUINTEL}inline;{$ENDIF}
  101. // pure pascal implementation of xxHash32
  102. function xxHash32Pascal(crc: cardinal; P: Pointer; len: integer): cardinal;
  103. type
  104. THasher = function(crc: cardinal; buf: Pointer; len: cardinal): cardinal;
  105. var
  106. crc32c: THasher;
  107. mORMotHasher: THasher;
  108. implementation
  109. {$IFDEF FPC_DOTTEDUNITS}
  110. {$ifdef CPUINTEL}
  111. uses
  112. System.CPU;
  113. {$endif CPUINTEL}
  114. {$ELSE}
  115. {$ifdef CPUINTEL}
  116. uses
  117. cpu;
  118. {$endif CPUINTEL}
  119. {$ENDIF}
  120. function SimpleChecksumHash(AKey: Pointer; ALength: SizeInt): UInt32;
  121. var
  122. i: Integer;
  123. ABuffer: PUInt8 absolute AKey;
  124. begin
  125. Result := 0;
  126. for i := 0 to ALength - 1 do
  127. Inc(Result,ABuffer[i]);
  128. end;
  129. function Adler32(AKey: Pointer; ALength: SizeInt): UInt32;
  130. const
  131. MOD_ADLER = 65521;
  132. var
  133. ABuffer: PUInt8 absolute AKey;
  134. a: UInt32 = 1;
  135. b: UInt32 = 0;
  136. n: Integer;
  137. begin
  138. for n := 0 to ALength -1 do
  139. begin
  140. a := (a + ABuffer[n]) mod MOD_ADLER;
  141. b := (b + a) mod MOD_ADLER;
  142. end;
  143. Result := (b shl 16) or a;
  144. end;
  145. function sdbm(AKey: Pointer; ALength: SizeInt): UInt32;
  146. var
  147. c: PUInt8 absolute AKey;
  148. i: Integer;
  149. begin
  150. Result := 0;
  151. c := AKey;
  152. for i := 0 to ALength - 1 do
  153. begin
  154. Result := c^ + (Result shl 6) + (Result shl 16) {%H-}- Result;
  155. Inc(c);
  156. end;
  157. end;
  158. { BobJenkinsHash }
  159. {$define mix_abc :=
  160. a -= c; a := a xor (((c)shl(4)) or ((c)shr(32-(4)))); c += b;
  161. b -= a; b := b xor (((a)shl(6)) or ((a)shr(32-(6)))); a += c;
  162. c -= b; c := c xor (((b)shl(8)) or ((b)shr(32-(8)))); b += a;
  163. a -= c; a := a xor (((c)shl(16)) or ((c)shr(32-(16)))); c += b;
  164. b -= a; b := b xor (((a)shl(19)) or ((a)shr(32-(19)))); a += c;
  165. c -= b; c := c xor (((b)shl(4)) or ((b)shr(32-(4)))); b += a
  166. }
  167. {$define final_abc :=
  168. c := c xor b; c -= (((b)shl(14)) or ((b)shr(32-(14))));
  169. a := a xor c; a -= (((c)shl(11)) or ((c)shr(32-(11))));
  170. b := b xor a; b -= (((a)shl(25)) or ((a)shr(32-(25))));
  171. c := c xor b; c -= (((b)shl(16)) or ((b)shr(32-(16))));
  172. a := a xor c; a -= (((c)shl(4)) or ((c)shr(32-(4))));
  173. b := b xor a; b -= (((a)shl(14)) or ((a)shr(32-(14))));
  174. c := c xor b; c -= (((b)shl(24)) or ((b)shr(32-(24))))
  175. }
  176. function HashWord(
  177. AKey: PLongWord; //* the key, an array of uint32_t values */
  178. ALength: SizeInt; //* the length of the key, in uint32_ts */
  179. AInitVal: UInt32): UInt32; //* the previous hash, or an arbitrary value */
  180. var
  181. a,b,c: UInt32;
  182. {$IFNDEF NOGOTO}
  183. label
  184. Case0, Case1, Case2, Case3;
  185. {$ENDIF}
  186. begin
  187. //* Set up the internal state */
  188. a := $DEADBEEF + (UInt32(ALength) shl 2) + AInitVal;
  189. b := a;
  190. c := b;
  191. //*------------------------------------------------- handle most of the key */
  192. while ALength > 3 do
  193. begin
  194. a += AKey[0];
  195. b += AKey[1];
  196. c += AKey[2];
  197. mix_abc;
  198. ALength -= 3;
  199. AKey += 3;
  200. end;
  201. //*------------------------------------------- handle the last 3 uint32_t's */
  202. {$IFDEF NOGOTO}
  203. if aLength=3 then
  204. c+=AKey[2];
  205. if aLength>=2 then
  206. b+=AKey[1];
  207. if aLength>=1 then
  208. a+=AKey[0];
  209. if aLength>0 then
  210. final_abc;
  211. {$ELSE}
  212. case ALength of //* all the case statements fall through */
  213. 3: goto Case3;
  214. 2: goto Case2;
  215. 1: goto Case1;
  216. 0: goto Case0;
  217. end;
  218. Case3: c+=AKey[2];
  219. Case2: b+=AKey[1];
  220. Case1: a+=AKey[0];
  221. final_abc;
  222. Case0: //* case 0: nothing left to add */
  223. {$ENDIF}
  224. //*------------------------------------------------------ report the result */
  225. Result := c;
  226. end;
  227. procedure HashWord2 (
  228. AKey: PLongWord; //* the key, an array of uint32_t values */
  229. ALength: SizeInt; //* the length of the key, in uint32_ts */
  230. var APrimaryHashAndInitVal: UInt32; //* IN: seed OUT: primary hash value */
  231. var ASecondaryHashAndInitVal: UInt32); //* IN: more seed OUT: secondary hash value */
  232. var
  233. a,b,c: UInt32;
  234. {$IFNDEF NOGOTO}
  235. label
  236. Case0, Case1, Case2, Case3;
  237. {$ENDIF}
  238. begin
  239. //* Set up the internal state */
  240. a := $deadbeef + (UInt32(ALength shl 2)) + APrimaryHashAndInitVal;
  241. b := a;
  242. c := b;
  243. c += ASecondaryHashAndInitVal;
  244. //*------------------------------------------------- handle most of the key */
  245. while ALength > 3 do
  246. begin
  247. a += AKey[0];
  248. b += AKey[1];
  249. c += AKey[2];
  250. mix_abc;
  251. ALength -= 3;
  252. AKey += 3;
  253. end;
  254. //*------------------------------------------- handle the last 3 uint32_t's */
  255. {$IFDEF NOGOTO}
  256. if aLength=3 then
  257. c+=AKey[2];
  258. if aLength>=2 then
  259. b+=AKey[1];
  260. if aLength>=1 then
  261. a+=AKey[0];
  262. if aLength>0 then
  263. final_abc;
  264. {$ELSE}
  265. case ALength of //* all the case statements fall through */
  266. 3: goto Case3;
  267. 2: goto Case2;
  268. 1: goto Case1;
  269. 0: goto Case0;
  270. end;
  271. Case3: c+=AKey[2];
  272. Case2: b+=AKey[1];
  273. Case1: a+=AKey[0];
  274. final_abc;
  275. Case0: //* case 0: nothing left to add */
  276. {$ENDIF}
  277. //*------------------------------------------------------ report the result */
  278. APrimaryHashAndInitVal := c;
  279. ASecondaryHashAndInitVal := b;
  280. end;
  281. function HashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): UInt32;
  282. var
  283. a, b, c: UInt32;
  284. u: record case byte of
  285. 0: (ptr: Pointer);
  286. 1: (i: PtrUint);
  287. end absolute AKey;
  288. k32: ^UInt32 absolute AKey;
  289. k16: ^UInt16 absolute AKey;
  290. k8: ^UInt8 absolute AKey;
  291. {$IFNDEF NOGOTO}
  292. label _10, _8, _6, _4, _2;
  293. label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
  294. {$endif}
  295. {$IFDEF NOGOTO}
  296. procedure Do10; inline;
  297. begin
  298. c+=k16[4];
  299. b+=k16[2]+((UInt32(k16[3])) shl 16);
  300. a+=k16[0]+((UInt32(k16[1])) shl 16);
  301. end;
  302. procedure Do8; inline;
  303. begin
  304. b+=k16[2]+((UInt32(k16[3])) shl 16);
  305. a+=k16[0]+((UInt32(k16[1])) shl 16);
  306. end;
  307. procedure Do6; inline;
  308. begin
  309. b+=k16[2];
  310. a+=k16[0]+((UInt32(k16[1])) shl 16);
  311. end;
  312. procedure Do4; inline;
  313. begin
  314. a+=k16[0]+((UInt32(k16[1])) shl 16);
  315. end;
  316. procedure Do2; inline;
  317. begin
  318. a+=k16[0];
  319. end;
  320. {$ENDIF}
  321. begin
  322. a := $DEADBEEF + UInt32(ALength) + AInitVal;
  323. b := a;
  324. c := b;
  325. {$IFDEF ENDIAN_LITTLE}
  326. if (u.i and $3) = 0 then
  327. begin
  328. while (ALength > 12) do
  329. begin
  330. a += k32[0];
  331. b += k32[1];
  332. c += k32[2];
  333. mix_abc;
  334. ALength -= 12;
  335. k32 += 3;
  336. end;
  337. case ALength of
  338. 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
  339. 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
  340. 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
  341. 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
  342. 8 : begin b += k32[1]; a += k32[0]; end;
  343. 7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
  344. 6 : begin b += k32[1] and $ffff; a += k32[0]; end;
  345. 5 : begin b += k32[1] and $ff; a += k32[0]; end;
  346. 4 : begin a += k32[0]; end;
  347. 3 : begin a += k32[0] and $ffffff; end;
  348. 2 : begin a += k32[0] and $ffff; end;
  349. 1 : begin a += k32[0] and $ff; end;
  350. 0 : Exit(c); // zero length strings require no mixing
  351. end
  352. end
  353. else
  354. if (u.i and $1) = 0 then
  355. begin
  356. while (ALength > 12) do
  357. begin
  358. a += k16[0] + (UInt32(k16[1]) shl 16);
  359. b += k16[2] + (UInt32(k16[3]) shl 16);
  360. c += k16[4] + (UInt32(k16[5]) shl 16);
  361. mix_abc;
  362. ALength -= 12;
  363. k16 += 6;
  364. end;
  365. case ALength of
  366. 12:
  367. begin
  368. c+=k16[4]+((UInt32(k16[5])) shl 16);
  369. b+=k16[2]+((UInt32(k16[3])) shl 16);
  370. a+=k16[0]+((UInt32(k16[1])) shl 16);
  371. end;
  372. 11:
  373. begin
  374. c+=(UInt32(k8[10])) shl 16; //* fall through */
  375. {$IFDEF NOGOTO}
  376. do10;
  377. {$ELSE}
  378. goto _10;
  379. {$ENDIF}
  380. end;
  381. 10:
  382. begin
  383. {$IFDEF NOGOTO}
  384. do10;
  385. {$ELSE}
  386. _10:
  387. c+=k16[4];
  388. b+=k16[2]+((UInt32(k16[3])) shl 16);
  389. a+=k16[0]+((UInt32(k16[1])) shl 16);
  390. {$ENDIF}
  391. end;
  392. 9 :
  393. begin
  394. c+=k8[8]; //* fall through */
  395. {$IFDEF NOGOTO}
  396. do8;
  397. {$ELSE}
  398. goto _8;
  399. {$ENDIF}
  400. end;
  401. 8 :
  402. begin
  403. {$IFDEF NOGOTO}
  404. do8;
  405. {$ELSE}
  406. _8:
  407. b+=k16[2]+((UInt32(k16[3])) shl 16);
  408. a+=k16[0]+((UInt32(k16[1])) shl 16);
  409. {$ENDIF}
  410. end;
  411. 7 :
  412. begin
  413. b+=(UInt32(k8[6])) shl 16; //* fall through */
  414. {$IFDEF NOGOTO}
  415. Do6 ;
  416. {$ELSE}
  417. goto _6;
  418. {$ENDIF}
  419. end;
  420. 6 :
  421. begin
  422. {$IFDEF NOGOTO}
  423. Do6 ;
  424. {$ELSE}
  425. _6:
  426. b+=k16[2];
  427. a+=k16[0]+((UInt32(k16[1])) shl 16);
  428. {$ENDIF}
  429. end;
  430. 5 :
  431. begin
  432. b+=k8[4]; //* fall through */
  433. {$IFDEF NOGOTO}
  434. Do4;
  435. {$ELSE}
  436. goto _4;
  437. {$ENDIF}
  438. end;
  439. 4 :
  440. begin
  441. {$IFDEF NOGOTO}
  442. Do4;
  443. {$ELSE}
  444. _4:
  445. a+=k16[0]+((UInt32(k16[1])) shl 16);
  446. {$ENDIF}
  447. end;
  448. 3 :
  449. begin
  450. a+=(UInt32(k8[2])) shl 16; //* fall through */
  451. {$IFDEF NOGOTO}
  452. do2;
  453. {$ELSE}
  454. goto _2;
  455. {$ENDIF}
  456. end;
  457. 2 :
  458. begin
  459. {$IFDEF NOGOTO}
  460. do2;
  461. {$ELSE}
  462. _2:
  463. a+=k16[0];
  464. {$ENDIF}
  465. end;
  466. 1 :
  467. begin
  468. a+=k8[0];
  469. end;
  470. 0 : Exit(c); //* zero length requires no mixing */
  471. end;
  472. end
  473. else
  474. {$ENDIF}
  475. begin
  476. while ALength > 12 do
  477. begin
  478. a += k8[0];
  479. a += (UInt32(k8[1])) shl 8;
  480. a += (UInt32(k8[2])) shl 16;
  481. a += (UInt32(k8[3])) shl 24;
  482. b += k8[4];
  483. b += (UInt32(k8[5])) shl 8;
  484. b += (UInt32(k8[6])) shl 16;
  485. b += (UInt32(k8[7])) shl 24;
  486. c += k8[8];
  487. c += (UInt32(k8[9])) shl 8;
  488. c += (UInt32(k8[10])) shl 16;
  489. c += (UInt32(k8[11])) shl 24;
  490. mix_abc;
  491. ALength -= 12;
  492. k8 += 12;
  493. end;
  494. {$IFDEF NOGOTO}
  495. if Alength=0 then
  496. Exit(c);
  497. if ALength=12 then
  498. c+=(UInt32(k8[11])) shl 24;
  499. if aLength>=11 then
  500. c+=(UInt32(k8[10])) shl 16;
  501. if aLength>=10 then
  502. c+=(UInt32(k8[9])) shl 8;
  503. if aLength>=9 then
  504. c+=k8[8];
  505. if aLength>=8 then
  506. b+=(UInt32(k8[7])) shl 24;
  507. if aLength>=7 then
  508. b+=(UInt32(k8[6])) shl 16;
  509. if aLength>=6 then
  510. b+=(UInt32(k8[5])) shl 8;
  511. if aLength>=5 then
  512. b+=k8[4];
  513. if aLength>=4 then
  514. a+=(UInt32(k8[3])) shl 24;
  515. if aLength>=3 then
  516. a+=(UInt32(k8[2])) shl 16;
  517. if aLength>=2 then
  518. a+=(UInt32(k8[1])) shl 8;
  519. // case aLength=0 was handled first, so we know aLength>=1.
  520. a+=k8[0];
  521. {$ELSE}
  522. case ALength of
  523. 12: goto Case12;
  524. 11: goto Case11;
  525. 10: goto Case10;
  526. 9 : goto Case9;
  527. 8 : goto Case8;
  528. 7 : goto Case7;
  529. 6 : goto Case6;
  530. 5 : goto Case5;
  531. 4 : goto Case4;
  532. 3 : goto Case3;
  533. 2 : goto Case2;
  534. 1 : goto Case1;
  535. 0 : Exit(c);
  536. end;
  537. Case12: c+=(UInt32(k8[11])) shl 24;
  538. Case11: c+=(UInt32(k8[10])) shl 16;
  539. Case10: c+=(UInt32(k8[9])) shl 8;
  540. Case9: c+=k8[8];
  541. Case8: b+=(UInt32(k8[7])) shl 24;
  542. Case7: b+=(UInt32(k8[6])) shl 16;
  543. Case6: b+=(UInt32(k8[5])) shl 8;
  544. Case5: b+=k8[4];
  545. Case4: a+=(UInt32(k8[3])) shl 24;
  546. Case3: a+=(UInt32(k8[2])) shl 16;
  547. Case2: a+=(UInt32(k8[1])) shl 8;
  548. Case1: a+=k8[0];
  549. {$ENDIF}
  550. end;
  551. final_abc;
  552. Result := c;
  553. end;
  554. (*
  555. * hashlittle2: return 2 32-bit hash values
  556. *
  557. * This is identical to hashlittle(), except it returns two 32-bit hash
  558. * values instead of just one. This is good enough for hash table
  559. * lookup with 2^^64 buckets, or if you want a second hash if you're not
  560. * happy with the first, or if you want a probably-unique 64-bit ID for
  561. * the key. *pc is better mixed than *pb, so use *pc first. If you want
  562. * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
  563. *)
  564. procedure HashLittle2(
  565. AKey: Pointer; //* the key to hash */
  566. ALength: SizeInt; //* length of the key */
  567. var APrimaryHashAndInitVal: UInt32; //* IN: primary initval, OUT: primary hash */
  568. var ASecondaryHashAndInitVal: UInt32); //* IN: secondary initval, OUT: secondary hash */
  569. var
  570. a,b,c: UInt32;
  571. u: record case byte of
  572. 0: (ptr: Pointer);
  573. 1: (i: PtrUint);
  574. end absolute AKey;
  575. k32: ^UInt32 absolute AKey;
  576. k16: ^UInt16 absolute AKey;
  577. k8: ^UInt8 absolute AKey;
  578. {$IFNDEF NOGOTO}
  579. label _10, _8, _6, _4, _2;
  580. label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
  581. {$ENDIF}
  582. {$IFDEF NOGOTO}
  583. procedure Do10; inline;
  584. begin
  585. c+=k16[4];
  586. b+=k16[2]+((UInt32(k16[3])) shl 16);
  587. a+=k16[0]+((UInt32(k16[1])) shl 16);
  588. end;
  589. procedure Do8; inline;
  590. begin
  591. b+=k16[2]+((UInt32(k16[3])) shl 16);
  592. a+=k16[0]+((UInt32(k16[1])) shl 16);
  593. end;
  594. procedure Do6; inline;
  595. begin
  596. b+=k16[2];
  597. a+=k16[0]+((UInt32(k16[1])) shl 16);
  598. end;
  599. procedure Do4; inline;
  600. begin
  601. a+=k16[0]+((UInt32(k16[1])) shl 16);
  602. end;
  603. procedure Do2; inline;
  604. begin
  605. a+=k16[0];
  606. end;
  607. {$ENDIF}
  608. begin
  609. //* Set up the internal state */
  610. a := $DEADBEEF + UInt32(ALength) + APrimaryHashAndInitVal;
  611. b := a;
  612. c := b;
  613. c += ASecondaryHashAndInitVal;
  614. {$IFDEF ENDIAN_LITTLE}
  615. if (u.i and $3) = 0 then
  616. begin
  617. while (ALength > 12) do
  618. begin
  619. a += k32[0];
  620. b += k32[1];
  621. c += k32[2];
  622. mix_abc;
  623. ALength -= 12;
  624. k32 += 3;
  625. end;
  626. case ALength of
  627. 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
  628. 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
  629. 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
  630. 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
  631. 8 : begin b += k32[1]; a += k32[0]; end;
  632. 7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
  633. 6 : begin b += k32[1] and $ffff; a += k32[0]; end;
  634. 5 : begin b += k32[1] and $ff; a += k32[0]; end;
  635. 4 : begin a += k32[0]; end;
  636. 3 : begin a += k32[0] and $ffffff; end;
  637. 2 : begin a += k32[0] and $ffff; end;
  638. 1 : begin a += k32[0] and $ff; end;
  639. 0 :
  640. begin
  641. APrimaryHashAndInitVal := c;
  642. ASecondaryHashAndInitVal := b;
  643. Exit; // zero length strings require no mixing
  644. end;
  645. end
  646. end
  647. else
  648. if (u.i and $1) = 0 then
  649. begin
  650. while (ALength > 12) do
  651. begin
  652. a += k16[0] + (UInt32(k16[1]) shl 16);
  653. b += k16[2] + (UInt32(k16[3]) shl 16);
  654. c += k16[4] + (UInt32(k16[5]) shl 16);
  655. mix_abc;
  656. ALength -= 12;
  657. k16 += 6;
  658. end;
  659. case ALength of
  660. 12:
  661. begin
  662. c+=k16[4]+((UInt32(k16[5])) shl 16);
  663. b+=k16[2]+((UInt32(k16[3])) shl 16);
  664. a+=k16[0]+((UInt32(k16[1])) shl 16);
  665. end;
  666. 11:
  667. begin
  668. c+=(UInt32(k8[10])) shl 16; //* fall through */
  669. {$IFDEF NOGOTO}
  670. Do10;
  671. {$ELSE}
  672. goto _10
  673. {$ENDIF}
  674. end;
  675. 10:
  676. begin
  677. {$IFDEF NOGOTO}
  678. Do10;
  679. {$ELSE}
  680. _10:
  681. c+=k16[4];
  682. b+=k16[2]+((UInt32(k16[3])) shl 16);
  683. a+=k16[0]+((UInt32(k16[1])) shl 16);
  684. {$ENDIF}
  685. end;
  686. 9 :
  687. begin
  688. c+=k8[8]; //* fall through */
  689. {$IFDEF NOGOTO}
  690. Do8;
  691. {$ELSE}
  692. goto _8;
  693. {$ENDIF}
  694. end;
  695. 8 :
  696. begin
  697. {$IFDEF NOGOTO}
  698. Do8;
  699. {$ELSE}
  700. _8:
  701. b+=k16[2]+((UInt32(k16[3])) shl 16);
  702. a+=k16[0]+((UInt32(k16[1])) shl 16);
  703. {$ENDIF}
  704. end;
  705. 7 :
  706. begin
  707. b+=(UInt32(k8[6])) shl 16; //* fall through */
  708. {$IFDEF NOGOTO}
  709. Do6 ;
  710. {$ELSE}
  711. goto _6;
  712. {$ENDIF}
  713. end;
  714. 6 :
  715. begin
  716. {$IFDEF NOGOTO}
  717. Do6 ;
  718. {$ELSE}
  719. _6:
  720. b+=k16[2];
  721. a+=k16[0]+((UInt32(k16[1])) shl 16);
  722. {$ENDIF}
  723. end;
  724. 5 :
  725. begin
  726. b+=k8[4]; //* fall through */
  727. {$IFDEF NOGOTO}
  728. Do4 ;
  729. {$ELSE}
  730. goto _4;
  731. {$ENDIF}
  732. end;
  733. 4 :
  734. begin
  735. {$IFDEF NOGOTO}
  736. Do4 ;
  737. {$ELSE}
  738. _4:
  739. a+=k16[0]+((UInt32(k16[1])) shl 16);
  740. {$ENDIF}
  741. end;
  742. 3 :
  743. begin
  744. a+=(UInt32(k8[2])) shl 16; //* fall through */
  745. {$IFDEF NOGOTO}
  746. Do2 ;
  747. {$ELSE}
  748. goto _2;
  749. {$ENDIF}
  750. end;
  751. 2 :
  752. begin
  753. {$IFDEF NOGOTO}
  754. Do2;
  755. {$ELSE}
  756. _2:
  757. a+=k16[0];
  758. {$ENDIF}
  759. end;
  760. 1 :
  761. begin
  762. a+=k8[0];
  763. end;
  764. 0 :
  765. begin
  766. APrimaryHashAndInitVal := c;
  767. ASecondaryHashAndInitVal := b;
  768. Exit; // zero length strings require no mixing
  769. end;
  770. end;
  771. end
  772. else
  773. {$ENDIF}
  774. begin
  775. while ALength > 12 do
  776. begin
  777. a += k8[0];
  778. a += (UInt32(k8[1])) shl 8;
  779. a += (UInt32(k8[2])) shl 16;
  780. a += (UInt32(k8[3])) shl 24;
  781. b += k8[4];
  782. b += (UInt32(k8[5])) shl 8;
  783. b += (UInt32(k8[6])) shl 16;
  784. b += (UInt32(k8[7])) shl 24;
  785. c += k8[8];
  786. c += (UInt32(k8[9])) shl 8;
  787. c += (UInt32(k8[10])) shl 16;
  788. c += (UInt32(k8[11])) shl 24;
  789. mix_abc;
  790. ALength -= 12;
  791. k8 += 12;
  792. end;
  793. {$IFDEF NOGOTO}
  794. if aLength=0 then
  795. begin
  796. APrimaryHashAndInitVal := c;
  797. ASecondaryHashAndInitVal := b;
  798. Exit; // zero length strings require no mixing
  799. end;
  800. if aLength=12 then
  801. c+=(UInt32(k8[11])) shl 24;
  802. if aLength>=11 then
  803. c+=(UInt32(k8[10])) shl 16;
  804. if aLength>=10 then
  805. c+=(UInt32(k8[9])) shl 8;
  806. if aLength>=9 then
  807. c+=k8[8];
  808. if aLength>=8 then
  809. b+=(UInt32(k8[7])) shl 24;
  810. if aLength>=7 then
  811. b+=(UInt32(k8[6])) shl 16;
  812. if aLength>=6 then
  813. b+=(UInt32(k8[5])) shl 8;
  814. if aLength>=5 then
  815. b+=k8[4];
  816. if aLength>=4 then
  817. a+=(UInt32(k8[3])) shl 24;
  818. if aLength>=3 then
  819. a+=(UInt32(k8[2])) shl 16;
  820. if aLength>=2 then
  821. a+=(UInt32(k8[1])) shl 8;
  822. a+=k8[0];
  823. {$ELSE}
  824. case ALength of
  825. 12: goto Case12;
  826. 11: goto Case11;
  827. 10: goto Case10;
  828. 9 : goto Case9;
  829. 8 : goto Case8;
  830. 7 : goto Case7;
  831. 6 : goto Case6;
  832. 5 : goto Case5;
  833. 4 : goto Case4;
  834. 3 : goto Case3;
  835. 2 : goto Case2;
  836. 1 : goto Case1;
  837. 0 :
  838. begin
  839. APrimaryHashAndInitVal := c;
  840. ASecondaryHashAndInitVal := b;
  841. Exit; // zero length strings require no mixing
  842. end;
  843. end;
  844. Case12: c+=(UInt32(k8[11])) shl 24;
  845. Case11: c+=(UInt32(k8[10])) shl 16;
  846. Case10: c+=(UInt32(k8[9])) shl 8;
  847. Case9: c+=k8[8];
  848. Case8: b+=(UInt32(k8[7])) shl 24;
  849. Case7: b+=(UInt32(k8[6])) shl 16;
  850. Case6: b+=(UInt32(k8[5])) shl 8;
  851. Case5: b+=k8[4];
  852. Case4: a+=(UInt32(k8[3])) shl 24;
  853. Case3: a+=(UInt32(k8[2])) shl 16;
  854. Case2: a+=(UInt32(k8[1])) shl 8;
  855. Case1: a+=k8[0];
  856. {$ENDIF}
  857. end;
  858. final_abc;
  859. APrimaryHashAndInitVal := c;
  860. ASecondaryHashAndInitVal := b;
  861. end;
  862. procedure DelphiHashLittle2(AKey: Pointer; ALength: SizeInt; var APrimaryHashAndInitVal, ASecondaryHashAndInitVal: UInt32);
  863. var
  864. a,b,c: UInt32;
  865. u: record case byte of
  866. 0: (ptr: Pointer);
  867. 1: (i: PtrUint);
  868. end absolute AKey;
  869. k32: ^UInt32 absolute AKey;
  870. k16: ^UInt16 absolute AKey;
  871. k8: ^UInt8 absolute AKey;
  872. {$IFNDEF NOGOTO}
  873. label _10, _8, _6, _4, _2;
  874. label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
  875. {$ENDIF}
  876. {$IFDEF NOGOTO}
  877. procedure Do10; inline;
  878. begin
  879. c+=k16[4];
  880. b+=k16[2]+((UInt32(k16[3])) shl 16);
  881. a+=k16[0]+((UInt32(k16[1])) shl 16);
  882. end;
  883. procedure Do8; inline;
  884. begin
  885. b+=k16[2]+((UInt32(k16[3])) shl 16);
  886. a+=k16[0]+((UInt32(k16[1])) shl 16);
  887. end;
  888. procedure Do6; inline;
  889. begin
  890. b+=k16[2];
  891. a+=k16[0]+((UInt32(k16[1])) shl 16);
  892. end;
  893. procedure Do4; inline;
  894. begin
  895. a+=k16[0]+((UInt32(k16[1])) shl 16);
  896. end;
  897. procedure Do2; inline;
  898. begin
  899. a+=k16[0];
  900. end;
  901. {$ENDIF}
  902. begin
  903. //* Set up the internal state */
  904. a := $DEADBEEF + UInt32(ALength) + APrimaryHashAndInitVal;
  905. b := a;
  906. c := b;
  907. c += ASecondaryHashAndInitVal;
  908. {$IFDEF ENDIAN_LITTLE}
  909. if (u.i and $3) = 0 then
  910. begin
  911. while (ALength > 12) do
  912. begin
  913. a += k32[0];
  914. b += k32[1];
  915. c += k32[2];
  916. mix_abc;
  917. ALength -= 12;
  918. k32 += 3;
  919. end;
  920. case ALength of
  921. 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
  922. 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
  923. 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
  924. 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
  925. 8 : begin b += k32[1]; a += k32[0]; end;
  926. 7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
  927. 6 : begin b += k32[1] and $ffff; a += k32[0]; end;
  928. 5 : begin b += k32[1] and $ff; a += k32[0]; end;
  929. 4 : begin a += k32[0]; end;
  930. 3 : begin a += k32[0] and $ffffff; end;
  931. 2 : begin a += k32[0] and $ffff; end;
  932. 1 : begin a += k32[0] and $ff; end;
  933. 0 :
  934. begin
  935. APrimaryHashAndInitVal := c;
  936. ASecondaryHashAndInitVal := b;
  937. Exit; // zero length strings require no mixing
  938. end;
  939. end
  940. end
  941. else
  942. if (u.i and $1) = 0 then
  943. begin
  944. while (ALength > 12) do
  945. begin
  946. a += k16[0] + (UInt32(k16[1]) shl 16);
  947. b += k16[2] + (UInt32(k16[3]) shl 16);
  948. c += k16[4] + (UInt32(k16[5]) shl 16);
  949. mix_abc;
  950. ALength -= 12;
  951. k16 += 6;
  952. end;
  953. case ALength of
  954. 12:
  955. begin
  956. c+=k16[4]+((UInt32(k16[5])) shl 16);
  957. b+=k16[2]+((UInt32(k16[3])) shl 16);
  958. a+=k16[0]+((UInt32(k16[1])) shl 16);
  959. end;
  960. 11:
  961. begin
  962. c+=(UInt32(k8[10])) shl 16; //* fall through */
  963. {$IFDEF NOGOTO}
  964. Do10;
  965. {$ELSE}
  966. goto _10;
  967. {$ENDIF}
  968. end;
  969. 10:
  970. begin
  971. {$IFDEF NOGOTO}
  972. Do10;
  973. {$ELSE}
  974. _10:
  975. c+=k16[4];
  976. b+=k16[2]+((UInt32(k16[3])) shl 16);
  977. a+=k16[0]+((UInt32(k16[1])) shl 16);
  978. {$ENDIF}
  979. end;
  980. 9 :
  981. begin
  982. c+=k8[8]; //* fall through */
  983. {$IFDEF NOGOTO}
  984. Do8;
  985. {$ELSE}
  986. goto _8;
  987. {$ENDIF}
  988. end;
  989. 8 :
  990. begin
  991. {$IFDEF NOGOTO}
  992. Do8;
  993. {$ELSE}
  994. _8:
  995. b+=k16[2]+((UInt32(k16[3])) shl 16);
  996. a+=k16[0]+((UInt32(k16[1])) shl 16);
  997. {$ENDIF}
  998. end;
  999. 7 :
  1000. begin
  1001. b+=(UInt32(k8[6])) shl 16; //* fall through */
  1002. {$IFDEF NOGOTO}
  1003. Do6;
  1004. {$ELSE}
  1005. goto _6;
  1006. {$ENDIF}
  1007. end;
  1008. 6 :
  1009. begin
  1010. {$IFDEF NOGOTO}
  1011. Do6;
  1012. {$ELSE}
  1013. _6:
  1014. b+=k16[2];
  1015. a+=k16[0]+((UInt32(k16[1])) shl 16);
  1016. {$ENDIF}
  1017. end;
  1018. 5 :
  1019. begin
  1020. b+=k8[4]; //* fall through */
  1021. {$IFDEF NOGOTO}
  1022. Do4;
  1023. {$ELSE}
  1024. goto _4;
  1025. {$ENDIF}
  1026. end;
  1027. 4 :
  1028. begin
  1029. {$IFDEF NOGOTO}
  1030. Do4;
  1031. {$ELSE}
  1032. _4:
  1033. a+=k16[0]+((UInt32(k16[1])) shl 16);
  1034. {$ENDIF}
  1035. end;
  1036. 3 :
  1037. begin
  1038. a+=(UInt32(k8[2])) shl 16; //* fall through */
  1039. {$IFDEF NOGOTO}
  1040. Do2;
  1041. {$ELSE}
  1042. goto _2;
  1043. {$ENDIF}
  1044. end;
  1045. 2 :
  1046. begin
  1047. {$IFDEF NOGOTO}
  1048. Do2;
  1049. {$ELSE}
  1050. _2:
  1051. a+=k16[0];
  1052. {$ENDIF}
  1053. end;
  1054. 1 :
  1055. begin
  1056. a+=k8[0];
  1057. end;
  1058. 0 :
  1059. begin
  1060. APrimaryHashAndInitVal := c;
  1061. ASecondaryHashAndInitVal := b;
  1062. Exit; // zero length strings require no mixing
  1063. end;
  1064. end;
  1065. end
  1066. else
  1067. {$ENDIF}
  1068. begin
  1069. while ALength > 12 do
  1070. begin
  1071. a += k8[0];
  1072. a += (UInt32(k8[1])) shl 8;
  1073. a += (UInt32(k8[2])) shl 16;
  1074. a += (UInt32(k8[3])) shl 24;
  1075. b += k8[4];
  1076. b += (UInt32(k8[5])) shl 8;
  1077. b += (UInt32(k8[6])) shl 16;
  1078. b += (UInt32(k8[7])) shl 24;
  1079. c += k8[8];
  1080. c += (UInt32(k8[9])) shl 8;
  1081. c += (UInt32(k8[10])) shl 16;
  1082. c += (UInt32(k8[11])) shl 24;
  1083. mix_abc;
  1084. ALength -= 12;
  1085. k8 += 12;
  1086. end;
  1087. {$IFDEF NOGOTO}
  1088. if aLength=0 then
  1089. begin
  1090. APrimaryHashAndInitVal := c;
  1091. ASecondaryHashAndInitVal := b;
  1092. Exit; // zero length strings require no mixing
  1093. end;
  1094. if aLength=12 then
  1095. c+=(UInt32(k8[11])) shl 24;
  1096. if aLength>=11 then
  1097. c+=(UInt32(k8[10])) shl 16;
  1098. if aLength>=10 then
  1099. c+=(UInt32(k8[9])) shl 8;
  1100. if aLength>=9 then
  1101. c+=k8[8];
  1102. if aLength>=8 then
  1103. b+=(UInt32(k8[7])) shl 24;
  1104. if aLength>=7 then
  1105. b+=(UInt32(k8[6])) shl 16;
  1106. if aLength>=6 then
  1107. b+=(UInt32(k8[5])) shl 8;
  1108. if aLength>=5 then
  1109. b+=k8[4];
  1110. if aLength>=4 then
  1111. a+=(UInt32(k8[3])) shl 24;
  1112. if aLength>=3 then
  1113. a+=(UInt32(k8[2])) shl 16;
  1114. if aLength>=2 then
  1115. a+=(UInt32(k8[1])) shl 8;
  1116. a+=k8[0];
  1117. {$ELSE}
  1118. case ALength of
  1119. 12: goto Case12;
  1120. 11: goto Case11;
  1121. 10: goto Case10;
  1122. 9 : goto Case9;
  1123. 8 : goto Case8;
  1124. 7 : goto Case7;
  1125. 6 : goto Case6;
  1126. 5 : goto Case5;
  1127. 4 : goto Case4;
  1128. 3 : goto Case3;
  1129. 2 : goto Case2;
  1130. 1 : goto Case1;
  1131. 0 :
  1132. begin
  1133. APrimaryHashAndInitVal := c;
  1134. ASecondaryHashAndInitVal := b;
  1135. Exit; // zero length strings require no mixing
  1136. end;
  1137. end;
  1138. Case12: c+=(UInt32(k8[11])) shl 24;
  1139. Case11: c+=(UInt32(k8[10])) shl 16;
  1140. Case10: c+=(UInt32(k8[9])) shl 8;
  1141. Case9: c+=k8[8];
  1142. Case8: b+=(UInt32(k8[7])) shl 24;
  1143. Case7: b+=(UInt32(k8[6])) shl 16;
  1144. Case6: b+=(UInt32(k8[5])) shl 8;
  1145. Case5: b+=k8[4];
  1146. Case4: a+=(UInt32(k8[3])) shl 24;
  1147. Case3: a+=(UInt32(k8[2])) shl 16;
  1148. Case2: a+=(UInt32(k8[1])) shl 8;
  1149. Case1: a+=k8[0];
  1150. {$ENDIF}
  1151. end;
  1152. final_abc;
  1153. APrimaryHashAndInitVal := c;
  1154. ASecondaryHashAndInitVal := b;
  1155. end;
  1156. function DelphiHashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): Int32;
  1157. var
  1158. a, b, c: UInt32;
  1159. u: record case byte of
  1160. 0: (ptr: Pointer);
  1161. 1: (i: PtrUint);
  1162. end absolute AKey;
  1163. k32: ^UInt32 absolute AKey;
  1164. //k16: ^UInt16 absolute AKey;
  1165. k8: ^UInt8 absolute AKey;
  1166. {$IFNDEF NOGOTO}
  1167. label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
  1168. {$ENDIF NOGOTO}
  1169. begin
  1170. a := $DEADBEEF + UInt32(ALength) + AInitVal;
  1171. b := a;
  1172. c := b;
  1173. {.$IFDEF ENDIAN_LITTLE} // Delphi version don't care
  1174. if (u.i and $3) = 0 then
  1175. begin
  1176. while (ALength > 12) do
  1177. begin
  1178. a += k32[0];
  1179. b += k32[1];
  1180. c += k32[2];
  1181. mix_abc;
  1182. ALength -= 12;
  1183. k32 += 3;
  1184. end;
  1185. case ALength of
  1186. 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
  1187. 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
  1188. 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
  1189. 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
  1190. 8 : begin b += k32[1]; a += k32[0]; end;
  1191. 7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
  1192. 6 : begin b += k32[1] and $ffff; a += k32[0]; end;
  1193. 5 : begin b += k32[1] and $ff; a += k32[0]; end;
  1194. 4 : begin a += k32[0]; end;
  1195. 3 : begin a += k32[0] and $ffffff; end;
  1196. 2 : begin a += k32[0] and $ffff; end;
  1197. 1 : begin a += k32[0] and $ff; end;
  1198. 0 : Exit(c); // zero length strings require no mixing
  1199. end
  1200. end
  1201. else
  1202. {.$ENDIF}
  1203. begin
  1204. while ALength > 12 do
  1205. begin
  1206. a += k8[0];
  1207. a += (UInt32(k8[1])) shl 8;
  1208. a += (UInt32(k8[2])) shl 16;
  1209. a += (UInt32(k8[3])) shl 24;
  1210. b += k8[4];
  1211. b += (UInt32(k8[5])) shl 8;
  1212. b += (UInt32(k8[6])) shl 16;
  1213. b += (UInt32(k8[7])) shl 24;
  1214. c += k8[8];
  1215. c += (UInt32(k8[9])) shl 8;
  1216. c += (UInt32(k8[10])) shl 16;
  1217. c += (UInt32(k8[11])) shl 24;
  1218. mix_abc;
  1219. ALength -= 12;
  1220. k8 += 12;
  1221. end;
  1222. {$IFDEF NOGOTO}
  1223. if aLength=0 then
  1224. exit(c);
  1225. if aLength=12 then
  1226. c+=(UInt32(k8[11])) shl 24;
  1227. if aLength>=11 then
  1228. c+=(UInt32(k8[10])) shl 16;
  1229. if aLength>=10 then
  1230. c+=(UInt32(k8[9])) shl 8;
  1231. if aLength>=9 then
  1232. c+=k8[8];
  1233. if aLength>=8 then
  1234. b+=(UInt32(k8[7])) shl 24;
  1235. if aLength>=7 then
  1236. b+=(UInt32(k8[6])) shl 16;
  1237. if aLength>=6 then
  1238. b+=(UInt32(k8[5])) shl 8;
  1239. if aLength>=5 then
  1240. b+=k8[4];
  1241. if aLength>=4 then
  1242. a+=(UInt32(k8[3])) shl 24;
  1243. if aLength>=3 then
  1244. a+=(UInt32(k8[2])) shl 16;
  1245. if aLength>=2 then
  1246. a+=(UInt32(k8[1])) shl 8;
  1247. a+=k8[0];
  1248. {$ELSE}
  1249. case ALength of
  1250. 12: goto Case12;
  1251. 11: goto Case11;
  1252. 10: goto Case10;
  1253. 9 : goto Case9;
  1254. 8 : goto Case8;
  1255. 7 : goto Case7;
  1256. 6 : goto Case6;
  1257. 5 : goto Case5;
  1258. 4 : goto Case4;
  1259. 3 : goto Case3;
  1260. 2 : goto Case2;
  1261. 1 : goto Case1;
  1262. 0 : Exit(c);
  1263. end;
  1264. Case12: c+=(UInt32(k8[11])) shl 24;
  1265. Case11: c+=(UInt32(k8[10])) shl 16;
  1266. Case10: c+=(UInt32(k8[9])) shl 8;
  1267. Case9: c+=k8[8];
  1268. Case8: b+=(UInt32(k8[7])) shl 24;
  1269. Case7: b+=(UInt32(k8[6])) shl 16;
  1270. Case6: b+=(UInt32(k8[5])) shl 8;
  1271. Case5: b+=k8[4];
  1272. Case4: a+=(UInt32(k8[3])) shl 24;
  1273. Case3: a+=(UInt32(k8[2])) shl 16;
  1274. Case2: a+=(UInt32(k8[1])) shl 8;
  1275. Case1: a+=k8[0];
  1276. {$ENDIF}
  1277. end;
  1278. final_abc;
  1279. Result := Int32(c);
  1280. end;
  1281. {$ifdef CPUARM} // circumvent FPC issue on ARM
  1282. function ToByte(value: cardinal): cardinal; inline;
  1283. begin
  1284. result := value and $ff;
  1285. end;
  1286. {$else}
  1287. type ToByte = byte;
  1288. {$endif}
  1289. {$ifdef CPUINTEL} // use optimized x86/x64 asm versions for xxHash32
  1290. {$ifdef CPUX86}
  1291. function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal;
  1292. asm
  1293. xchg edx, ecx
  1294. push ebp
  1295. push edi
  1296. lea ebp, [ecx+edx]
  1297. push esi
  1298. push ebx
  1299. sub esp, 8
  1300. cmp edx, 15
  1301. mov ebx, eax
  1302. mov dword ptr [esp], edx
  1303. lea eax, [ebx+165667B1H]
  1304. jbe @2
  1305. lea eax, [ebp-10H]
  1306. lea edi, [ebx+24234428H]
  1307. lea esi, [ebx-7A143589H]
  1308. mov dword ptr [esp+4H], ebp
  1309. mov edx, eax
  1310. lea eax, [ebx+61C8864FH]
  1311. mov ebp, edx
  1312. @1: mov edx, dword ptr [ecx]
  1313. imul edx, edx, -2048144777
  1314. add edi, edx
  1315. rol edi, 13
  1316. imul edi, edi, -1640531535
  1317. mov edx, dword ptr [ecx+4]
  1318. imul edx, edx, -2048144777
  1319. add esi, edx
  1320. rol esi, 13
  1321. imul esi, esi, -1640531535
  1322. mov edx, dword ptr [ecx+8]
  1323. imul edx, edx, -2048144777
  1324. add ebx, edx
  1325. rol ebx, 13
  1326. imul ebx, ebx, -1640531535
  1327. mov edx, dword ptr [ecx+12]
  1328. lea ecx, [ecx+16]
  1329. imul edx, edx, -2048144777
  1330. add eax, edx
  1331. rol eax, 13
  1332. imul eax, eax, -1640531535
  1333. cmp ebp, ecx
  1334. jnc @1
  1335. rol edi, 1
  1336. rol esi, 7
  1337. rol ebx, 12
  1338. add esi, edi
  1339. mov ebp, dword ptr [esp+4H]
  1340. ror eax, 14
  1341. add ebx, esi
  1342. add eax, ebx
  1343. @2: lea esi, [ecx+4H]
  1344. add eax, dword ptr [esp]
  1345. cmp ebp, esi
  1346. jc @4
  1347. mov ebx, esi
  1348. nop
  1349. @3: imul edx, dword ptr [ebx-4H], -1028477379
  1350. add ebx, 4
  1351. add eax, edx
  1352. ror eax, 15
  1353. imul eax, eax, 668265263
  1354. cmp ebp, ebx
  1355. jnc @3
  1356. lea edx, [ebp-4H]
  1357. sub edx, ecx
  1358. mov ecx, edx
  1359. and ecx, 0FFFFFFFCH
  1360. add ecx, esi
  1361. @4: cmp ebp, ecx
  1362. jbe @6
  1363. @5: movzx edx, byte ptr [ecx]
  1364. add ecx, 1
  1365. imul edx, edx, 374761393
  1366. add eax, edx
  1367. rol eax, 11
  1368. imul eax, eax, -1640531535
  1369. cmp ebp, ecx
  1370. jnz @5
  1371. nop
  1372. @6: mov edx, eax
  1373. add esp, 8
  1374. shr edx, 15
  1375. xor eax, edx
  1376. imul eax, eax, -2048144777
  1377. pop ebx
  1378. pop esi
  1379. mov edx, eax
  1380. shr edx, 13
  1381. xor eax, edx
  1382. imul eax, eax, -1028477379
  1383. pop edi
  1384. pop ebp
  1385. mov edx, eax
  1386. shr edx, 16
  1387. xor eax, edx
  1388. end;
  1389. {$endif CPUX86}
  1390. {$ifdef CPUX64}
  1391. function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal;
  1392. asm
  1393. {$ifndef WIN64} // crc=rdi P=rsi len=rdx
  1394. mov r8, rdi
  1395. mov rcx, rsi
  1396. {$else} // crc=r8 P=rcx len=rdx
  1397. mov r10, r8
  1398. mov r8, rcx
  1399. mov rcx, rdx
  1400. mov rdx, r10
  1401. push rsi // Win64 expects those registers to be preserved
  1402. push rdi
  1403. {$endif}
  1404. // P=r8 len=rcx crc=rdx
  1405. push rbx
  1406. lea r10, [rcx+rdx]
  1407. cmp rdx, 15
  1408. lea eax, [r8+165667B1H]
  1409. jbe @2
  1410. lea rsi, [r10-10H]
  1411. lea ebx, [r8+24234428H]
  1412. lea edi, [r8-7A143589H]
  1413. lea eax, [r8+61C8864FH]
  1414. @1: imul r9d, dword ptr [rcx], -2048144777
  1415. add rcx, 16
  1416. imul r11d, dword ptr [rcx-0CH], -2048144777
  1417. add ebx, r9d
  1418. lea r9d, [r11+rdi]
  1419. rol ebx, 13
  1420. rol r9d, 13
  1421. imul ebx, ebx, -1640531535
  1422. imul edi, r9d, -1640531535
  1423. imul r9d, dword ptr [rcx-8H], -2048144777
  1424. add r8d, r9d
  1425. imul r9d, dword ptr [rcx-4H], -2048144777
  1426. rol r8d, 13
  1427. imul r8d, r8d, -1640531535
  1428. add eax, r9d
  1429. rol eax, 13
  1430. imul eax, eax, -1640531535
  1431. cmp rsi, rcx
  1432. jnc @1
  1433. rol edi, 7
  1434. rol ebx, 1
  1435. rol r8d, 12
  1436. mov r9d, edi
  1437. ror eax, 14
  1438. add r9d, ebx
  1439. add r8d, r9d
  1440. add eax, r8d
  1441. @2: lea r9, [rcx+4H]
  1442. add eax, edx
  1443. cmp r10, r9
  1444. jc @4
  1445. mov r8, r9
  1446. @3: imul edx, dword ptr [r8-4H], -1028477379
  1447. add r8, 4
  1448. add eax, edx
  1449. ror eax, 15
  1450. imul eax, eax, 668265263
  1451. cmp r10, r8
  1452. jnc @3
  1453. lea rdx, [r10-4H]
  1454. sub rdx, rcx
  1455. mov rcx, rdx
  1456. and rcx, 0FFFFFFFFFFFFFFFCH
  1457. add rcx, r9
  1458. @4: cmp r10, rcx
  1459. jbe @6
  1460. @5: movzx edx, byte ptr [rcx]
  1461. add rcx, 1
  1462. imul edx, edx, 374761393
  1463. add eax, edx
  1464. rol eax, 11
  1465. imul eax, eax, -1640531535
  1466. cmp r10, rcx
  1467. jnz @5
  1468. @6: mov edx, eax
  1469. shr edx, 15
  1470. xor eax, edx
  1471. imul eax, eax, -2048144777
  1472. mov edx, eax
  1473. shr edx, 13
  1474. xor eax, edx
  1475. imul eax, eax, -1028477379
  1476. mov edx, eax
  1477. shr edx, 16
  1478. xor eax, edx
  1479. pop rbx
  1480. {$ifdef WIN64}
  1481. pop rdi
  1482. pop rsi
  1483. {$endif}
  1484. end;
  1485. {$endif CPUX64}
  1486. {$else not CPUINTEL}
  1487. function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal;
  1488. begin
  1489. result := xxHash32Pascal(crc, P, len);
  1490. end;
  1491. {$endif CPUINTEL}
  1492. const
  1493. PRIME32_1 = 2654435761;
  1494. PRIME32_2 = 2246822519;
  1495. PRIME32_3 = 3266489917;
  1496. PRIME32_4 = 668265263;
  1497. PRIME32_5 = 374761393;
  1498. // RolDWord is an intrinsic function under FPC :)
  1499. function Rol13(value: cardinal): cardinal; inline;
  1500. begin
  1501. result := RolDWord(value, 13);
  1502. end;
  1503. function xxHash32Pascal(crc: cardinal; P: Pointer; len: integer): cardinal;
  1504. var c1, c2, c3, c4: cardinal;
  1505. PLimit, PEnd: PAnsiChar;
  1506. begin
  1507. PEnd := P + len;
  1508. if len >= 16 then begin
  1509. PLimit := PEnd - 16;
  1510. c3 := crc;
  1511. c2 := c3 + PRIME32_2;
  1512. c1 := c2 + PRIME32_1;
  1513. c4 := c3 - PRIME32_1;
  1514. repeat
  1515. c1 := PRIME32_1 * Rol13(c1 + PRIME32_2 * PCardinal(P)^);
  1516. c2 := PRIME32_1 * Rol13(c2 + PRIME32_2 * PCardinal(P+4)^);
  1517. c3 := PRIME32_1 * Rol13(c3 + PRIME32_2 * PCardinal(P+8)^);
  1518. c4 := PRIME32_1 * Rol13(c4 + PRIME32_2 * PCardinal(P+12)^);
  1519. inc(P, 16);
  1520. until not (P <= PLimit);
  1521. result := RolDWord(c1, 1) + RolDWord(c2, 7) + RolDWord(c3, 12) + RolDWord(c4, 18);
  1522. end else
  1523. result := crc + PRIME32_5;
  1524. inc(result, len);
  1525. { Use "P + 4 <= PEnd" instead of "P <= PEnd - 4" to avoid crashes in case P = nil.
  1526. When P = nil,
  1527. then "PtrUInt(PEnd - 4)" is 4294967292,
  1528. so the condition "P <= PEnd - 4" would be satisfied,
  1529. and the code would try to access PCardinal(nil)^ causing a SEGFAULT. }
  1530. while P + 4 <= PEnd do begin
  1531. inc(result, PCardinal(P)^ * PRIME32_3);
  1532. result := RolDWord(result, 17) * PRIME32_4;
  1533. inc(P, 4);
  1534. end;
  1535. while P < PEnd do begin
  1536. inc(result, PByte(P)^ * PRIME32_5);
  1537. result := RolDWord(result, 11) * PRIME32_1;
  1538. inc(P);
  1539. end;
  1540. result := result xor (result shr 15);
  1541. result := result * PRIME32_2;
  1542. result := result xor (result shr 13);
  1543. result := result * PRIME32_3;
  1544. result := result xor (result shr 16);
  1545. end;
  1546. {$ifdef CPUINTEL}
  1547. {$ifdef CPU64}
  1548. function crc32csse42(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal; nostackframe; assembler;
  1549. asm
  1550. mov eax, crc
  1551. test len, len
  1552. jz @z
  1553. test buf, buf
  1554. jz @z
  1555. not eax
  1556. mov ecx, len
  1557. shr len, 3
  1558. jnz @by8 // we don't care for read alignment
  1559. @0: test cl, 4
  1560. jz @4
  1561. crc32 eax, dword ptr [buf]
  1562. add buf, 4
  1563. @4: test cl, 2
  1564. jz @2
  1565. crc32 eax, word ptr [buf]
  1566. add buf, 2
  1567. @2: test cl, 1
  1568. jz @1
  1569. crc32 eax, byte ptr [buf]
  1570. @1: not eax
  1571. @z: ret
  1572. align 16
  1573. @by8: crc32 rax, qword ptr [buf] // hash 8 bytes per loop
  1574. add buf, 8
  1575. sub len, 1
  1576. jnz @by8
  1577. jmp @0
  1578. end;
  1579. {$else}
  1580. function crc32csse42(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal; nostackframe; assembler;
  1581. asm
  1582. // eax=crc, edx=buf, ecx=len
  1583. not eax
  1584. test ecx, ecx
  1585. jz @0
  1586. test edx, edx
  1587. jz @0
  1588. jmp @align
  1589. @a: crc32 eax, byte ptr [edx]
  1590. inc edx
  1591. dec ecx
  1592. jz @0
  1593. @align: test dl, 3
  1594. jnz @a
  1595. push ecx
  1596. shr ecx, 3
  1597. jnz @by8
  1598. @rem: pop ecx
  1599. test cl, 4
  1600. jz @4
  1601. crc32 eax, dword ptr [edx]
  1602. add edx, 4
  1603. @4: test cl, 2
  1604. jz @2
  1605. crc32 eax, word ptr [edx]
  1606. add edx, 2
  1607. @2: test cl, 1
  1608. jz @0
  1609. crc32 eax, byte ptr [edx]
  1610. @0: not eax
  1611. ret
  1612. @by8: crc32 eax, dword ptr [edx]
  1613. crc32 eax, dword ptr [edx + 4]
  1614. add edx, 8
  1615. dec ecx
  1616. jnz @by8
  1617. jmp @rem
  1618. end;
  1619. {$endif}
  1620. {$endif CPUINTEL}
  1621. {$ifdef CPULOONGARCH64}
  1622. function crc32cloongarch(crc: cardinal; buf: Pointer; len: cardinal): cardinal; nostackframe; assembler;
  1623. asm
  1624. nor $a0, $zero, $a0
  1625. beqz $a1, .Lret
  1626. beqz $a2, .Lret
  1627. andi $t0, $a1, 7
  1628. beqz $t0, .Lcrc1
  1629. xori $t0, $t0, 7
  1630. .Lcrc0:
  1631. ld.b $t1, $a1, 0
  1632. addi.d $a1, $a1, 1
  1633. addi.d $t0, $t0, -1
  1634. addi.d $a2, $a2, -1
  1635. crcc.w.b.w $a0, $t1, $a0
  1636. beqz $a2, .Lret
  1637. bgez $t0, .Lcrc0
  1638. .Lcrc1:
  1639. srli.d $t0, $a2, 3
  1640. andi $t1, $a2, 4
  1641. andi $t2, $a2, 2
  1642. andi $t3, $a2, 1
  1643. beqz $t0, .Lcrc3
  1644. .Lcrc2:
  1645. ld.d $t4, $a1, 0
  1646. crcc.w.d.w $a0, $t4, $a0
  1647. addi.d $t0, $t0, -1
  1648. addi.d $a1, $a1, 8
  1649. bnez $t0, .Lcrc2
  1650. .Lcrc3:
  1651. beqz $t1,.Lcrc4
  1652. ld.w $t4, $a1, 0
  1653. crcc.w.w.w $a0, $t4, $a0
  1654. addi.d $a1, $a1, 4
  1655. .Lcrc4:
  1656. beqz $t2,.Lcrc5
  1657. ld.h $t4, $a1, 0
  1658. crcc.w.h.w $a0, $t4, $a0
  1659. addi.d $a1, $a1, 2
  1660. .Lcrc5:
  1661. beqz $t3,.Lret
  1662. ld.b $t4, $a1, 0
  1663. crcc.w.b.w $a0, $t4, $a0
  1664. .Lret:
  1665. nor $a0, $zero, $a0
  1666. end;
  1667. {$endif CPULOONGARCH64}
  1668. var
  1669. crc32ctab: array[0..{$ifdef PUREPASCAL}3{$else}7{$endif},byte] of cardinal;
  1670. function crc32cfast(crc: cardinal; buf: Pointer; len: cardinal): cardinal;
  1671. {$ifdef PUREPASCAL}
  1672. begin
  1673. result := not crc;
  1674. if (buf<>nil) and (len>0) then begin
  1675. repeat
  1676. if PtrUInt(buf) and 3=0 then // align to 4 bytes boundary
  1677. break;
  1678. result := crc32ctab[0,ToByte(result xor cardinal(buf^))] xor (result shr 8);
  1679. dec(len);
  1680. inc(buf);
  1681. until len=0;
  1682. while len>=4 do begin
  1683. result := result xor PCardinal(buf)^;
  1684. inc(buf,4);
  1685. result := crc32ctab[3,ToByte(result)] xor
  1686. crc32ctab[2,ToByte(result shr 8)] xor
  1687. crc32ctab[1,ToByte(result shr 16)] xor
  1688. crc32ctab[0,result shr 24];
  1689. dec(len,4);
  1690. end;
  1691. while len>0 do begin
  1692. result := crc32ctab[0,ToByte(result xor cardinal(buf^))] xor (result shr 8);
  1693. dec(len);
  1694. inc(buf);
  1695. end;
  1696. end;
  1697. result := not result;
  1698. end;
  1699. {$else}
  1700. // adapted from fast Aleksandr Sharahov version
  1701. asm
  1702. test edx, edx
  1703. jz @ret
  1704. neg ecx
  1705. jz @ret
  1706. not eax
  1707. push ebx
  1708. @head: test dl, 3
  1709. jz @aligned
  1710. movzx ebx, byte[edx]
  1711. inc edx
  1712. xor bl, al
  1713. shr eax, 8
  1714. xor eax, dword ptr[ebx * 4 + crc32ctab]
  1715. inc ecx
  1716. jnz @head
  1717. pop ebx
  1718. not eax
  1719. ret
  1720. @ret: rep ret
  1721. @aligned:
  1722. sub edx, ecx
  1723. add ecx, 8
  1724. jg @bodydone
  1725. push esi
  1726. push edi
  1727. mov edi, edx
  1728. mov edx, eax
  1729. @bodyloop:
  1730. mov ebx, [edi + ecx - 4]
  1731. xor edx, [edi + ecx - 8]
  1732. movzx esi, bl
  1733. mov eax, dword ptr[esi * 4 + crc32ctab + 1024 * 3]
  1734. movzx esi, bh
  1735. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 2]
  1736. shr ebx, 16
  1737. movzx esi, bl
  1738. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 1]
  1739. movzx esi, bh
  1740. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 0]
  1741. movzx esi, dl
  1742. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 7]
  1743. movzx esi, dh
  1744. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 6]
  1745. shr edx, 16
  1746. movzx esi, dl
  1747. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 5]
  1748. movzx esi, dh
  1749. xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 4]
  1750. add ecx, 8
  1751. jg @done
  1752. mov ebx, [edi + ecx - 4]
  1753. xor eax, [edi + ecx - 8]
  1754. movzx esi, bl
  1755. mov edx, dword ptr[esi * 4 + crc32ctab + 1024 * 3]
  1756. movzx esi, bh
  1757. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 2]
  1758. shr ebx, 16
  1759. movzx esi, bl
  1760. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 1]
  1761. movzx esi, bh
  1762. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 0]
  1763. movzx esi, al
  1764. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 7]
  1765. movzx esi, ah
  1766. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 6]
  1767. shr eax, 16
  1768. movzx esi, al
  1769. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 5]
  1770. movzx esi, ah
  1771. xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 4]
  1772. add ecx, 8
  1773. jle @bodyloop
  1774. mov eax, edx
  1775. @done: mov edx, edi
  1776. pop edi
  1777. pop esi
  1778. @bodydone:
  1779. sub ecx, 8
  1780. jl @tail
  1781. pop ebx
  1782. not eax
  1783. ret
  1784. @tail: movzx ebx, byte[edx + ecx]
  1785. xor bl, al
  1786. shr eax, 8
  1787. xor eax, dword ptr[ebx * 4 + crc32ctab]
  1788. inc ecx
  1789. jnz @tail
  1790. pop ebx
  1791. not eax
  1792. end;
  1793. {$endif PUREPASCAL}
  1794. procedure InitializeCrc32ctab;
  1795. var
  1796. i, n: integer;
  1797. crc: cardinal;
  1798. begin
  1799. // initialize tables for crc32cfast() and SymmetricEncrypt/FillRandom
  1800. for i := 0 to 255 do begin
  1801. crc := i;
  1802. for n := 1 to 8 do
  1803. if (crc and 1)<>0 then // polynom is not the same as with zlib's crc32()
  1804. crc := (crc shr 1) xor $82f63b78 else
  1805. crc := crc shr 1;
  1806. crc32ctab[0,i] := crc;
  1807. end;
  1808. for i := 0 to 255 do begin
  1809. crc := crc32ctab[0,i];
  1810. for n := 1 to high(crc32ctab) do begin
  1811. crc := (crc shr 8) xor crc32ctab[0,ToByte(crc)];
  1812. crc32ctab[n,i] := crc;
  1813. end;
  1814. end;
  1815. end;
  1816. begin
  1817. {$ifdef CPUINTEL}
  1818. if SSE42Support then
  1819. begin
  1820. crc32c := @crc32csse42;
  1821. mORMotHasher := @crc32csse42;
  1822. end
  1823. else
  1824. {$endif CPUINTEL}
  1825. {$ifdef CPULOONGARCH64}
  1826. if True then
  1827. begin
  1828. crc32c := @crc32cloongarch;
  1829. mORMotHasher := @crc32cloongarch;
  1830. end
  1831. else
  1832. {$endif CPULOONGARCH64}
  1833. begin
  1834. InitializeCrc32ctab;
  1835. crc32c := @crc32cfast;
  1836. mORMotHasher := @{$IFDEF CPUINTEL}xxHash32{$ELSE}xxHash32Pascal{$ENDIF};
  1837. end;
  1838. end.