1 /****************************************************************************** 2 3 TODO: move module to ocean.util.digest 4 5 Copyright: 6 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 7 All rights reserved. 8 9 License: 10 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 11 Alternatively, this file may be distributed under the terms of the Tango 12 3-Clause BSD License (see LICENSE_BSD.txt for details). 13 14 *******************************************************************************/ 15 16 module ocean.io.digest.Fnv1; 17 18 19 20 import ocean.meta.types.Qualifiers; 21 import ocean.util.digest.Digest; 22 23 import ocean.core.ByteSwap; 24 25 version (unittest) import ocean.core.Test; 26 27 28 /****************************************************************************** 29 30 template for creating FNV magic constants and endianness, depending on 31 if 32bit (uint) or 64bit (ulong) are used. 32 33 Params: 34 T = Type of hash to use, should be `uint` or `ulong`, or any alias 35 to them. Defaults to `hash_t`, which is a D alias to `size_t`. 36 37 *******************************************************************************/ 38 39 public template Fnv1Const ( T = hash_t ) 40 { 41 /************************************************************************** 42 43 FNV magic constants and endianness 44 45 **************************************************************************/ 46 47 public alias T DigestType; 48 49 static if (is (DigestType == uint)) 50 { 51 public static immutable DigestType PRIME = 0x0100_0193; // 32 bit prime 52 public static immutable DigestType INIT = 0x811C_9DC5; // 32 bit inital digest 53 public alias ByteSwap.swap32 toBigEnd; 54 } 55 else static if (is (DigestType == ulong)) 56 { 57 public static immutable DigestType PRIME = 0x0000_0100_0000_01B3; // 64 bit prime 58 public static immutable DigestType INIT = 0xCBF2_9CE4_8422_2325; // 64 bit inital digest 59 public alias ByteSwap.swap64 toBigEnd; 60 } 61 /* 62 // be prepared for the day when Walter introduces cent... 63 else static if (is (DigestType == ucent)) 64 { 65 public const DigestType PRIME = 0x0000_0000_0100_0000_0000_0000_0000_013B; // 128 bit prime 66 public const DigestType PRIME = 0x6C62_272E_07BB_0142_62B8_2175_6295_C58D; // 128 bit inital digest 67 } 68 */ 69 else static assert (false, "type '" ~ DigestType.stringof ~ 70 "' is not supported, only uint and ulong"); 71 } 72 73 74 /****************************************************************************** 75 76 Convenience aliases for 32-bit and 64-bit Fnv1 class template instances. 77 Must be defined after Fnv1Const to avoid DMD errors 78 79 *******************************************************************************/ 80 81 public alias Fnv1Generic!(true) Fnv1a; 82 public alias Fnv1Generic!(true, uint) Fnv1a32; 83 public alias Fnv1Generic!(true, ulong) Fnv1a64; 84 85 86 /****************************************************************************** 87 88 Compile time fnv1a hash function, calculates a hash value of type T where T 89 must be uint or ulong. 90 91 Convenience aliases for 32 bit (T = uint) or 64 bit (T = ulong) hashes are 92 defined below. They have to appear after this template definition because 93 DMD can currently (v1.075) not handle forward aliases in this case. 94 95 Params: 96 T = Type of hash to use, should be `uint` or `ulong`, or any alias 97 to them. Defaults to `hash_t`, which is a D alias to `size_t`. 98 99 *******************************************************************************/ 100 101 public template StaticFnv1a ( T = hash_t ) 102 { 103 /*************************************************************************** 104 105 Calculates the Fnv1a hash value of type T from input. 106 107 ***************************************************************************/ 108 109 public template Fnv1a ( istring input ) 110 { 111 public static immutable Fnv1a = Fnv1a!(Fnv1Const!(T).INIT, input); 112 } 113 114 /*************************************************************************** 115 116 Calculates the Fnv1a hash value of type T from input using hash as 117 initial hash value. 118 119 ***************************************************************************/ 120 121 public template Fnv1a ( T hash, istring input ) 122 { 123 static if ( input.length ) 124 { 125 public static immutable Fnv1a = Fnv1a!((hash ^ input[0]) * Fnv1Const!(T).PRIME, input[1 .. $]); 126 } 127 else 128 { 129 public static immutable Fnv1a = hash; 130 } 131 } 132 } 133 134 135 /****************************************************************************** 136 137 Aliases for Fnv1 32 and 64 bit magic constants. 138 139 *******************************************************************************/ 140 141 public alias Fnv1Const!(uint) Fnv132Const; 142 public alias Fnv1Const!(ulong) Fnv164Const; 143 144 /****************************************************************************** 145 146 Templates for compile-time FNV1a hashing. 147 148 *******************************************************************************/ 149 150 public template StaticFnv1a32 ( istring input ) 151 { 152 public static immutable StaticFnv1a32 = StaticFnv1a!(uint).Fnv1a!(input); 153 } 154 155 public template StaticFnv1a32 ( uint hash, istring input ) 156 { 157 public static immutable StaticFnv1a32 = StaticFnv1a!(uint).Fnv1a!(hash, input); 158 } 159 160 public template StaticFnv1a64 ( istring input ) 161 { 162 public static immutable StaticFnv1a64 = StaticFnv1a!(ulong).Fnv1a!(input); 163 } 164 165 public template StaticFnv1a64 ( ulong hash, istring input ) 166 { 167 public static immutable StaticFnv1a64 = StaticFnv1a!(ulong).Fnv1a!(hash, input); 168 } 169 170 171 /****************************************************************************** 172 173 abstract Fnv1 digest class 174 175 *******************************************************************************/ 176 177 public abstract class FnvDigest : Digest 178 { 179 /************************************************************************** 180 181 Simply returns the digest as an ulong independently of the digest size 182 and reset the internal state. 183 184 Returns: 185 digest 186 187 **************************************************************************/ 188 189 public abstract ulong ulongDigest ( ); 190 } 191 192 193 /******************************************************************************* 194 195 Fowler / Noll / Vo (FNV) 1/1a Hash Module 196 197 Very fast hashing algorithm implementation with support for 32/64 bit 198 hashes. 199 This modules implements two versions of FNV1: FNV1 and FNV1a. The 200 difference is extremely slight and Noll himself says: 201 202 "Some people use FNV1a instead of FNV1 because they see slightly 203 better dispersion for tiny (<4 octets) chunks of memory. Either 204 FNV-1 or FNV-1a make a fine hash." 205 206 (cited from http://www.isthe.com/chongo/tech/comp/fnv/) 207 208 209 The FNV1A template parameter selects FNV1a if set to true on 210 instantiation or FNV1 otherwise. It is recommended to use the 211 Fnv1XX/Fnv1aXX aliases. 212 213 Fnv1 and Fnv1a (without 32/64 suffix) use the native machine data word 214 width. 215 216 32bit ~ 3704333.44 hash/sec 217 64bit ~ 1728119.76 hash/sec 218 219 -- 220 221 Usage 222 223 It is recommended to use these Fnv1 class convenience aliases: 224 225 - Fnv1 for FNV1 digests of the machine's native width 226 - Fnv1a for FNV1a digests of the machine's native width 227 228 - Fnv132 for 32-bit FNV1 digests 229 - Fnv1a32 for 32-bit FNV1a digests 230 231 - Fnv164 for 64-bit FNV1 digests 232 - Fnv1a64 for 64-bit FNV1a digests 233 234 Example 1: Generating FNV1 digests using class instances 235 236 --- 237 238 import ocean.io.digest.Fnv1; 239 240 auto fnv1 = new Fnv1; 241 auto fnv132 = new Fnv132; 242 auto fnv164 = new Fnv164; 243 244 auto hello = "Hello World!"; 245 246 fnv1.update(hello); 247 fnv132.update(hello); 248 fnv164.update(hello); 249 250 auto hash = fnv1.hexDigest(); 251 auto hash32 = fnv132.hexDigest(); 252 auto hash64 = fnv164.hexDigest(); 253 254 --- 255 256 Example 2: Generating FNV1a digests using the static fnv1() method 257 258 --- 259 260 import ocean.io.digest.Fnv; 261 262 auto hello = "Hello World!"; 263 264 size_t hash = Fnv1a(hello); // size_t uses the native machine data word width 265 uint hash32 = Fnv1a32(hello); 266 ulong hash64 = Fnv1a64(hello); 267 268 --- 269 270 -- 271 272 We should use this hash algorithm in combination with this consistent 273 hash algorithm in order to build a distributed hash table (DTH) 274 275 http://www.audioscrobbler.net/development/ketama/ 276 svn://svn.audioscrobbler.net/misc/ketama/ 277 http://pdos.csail.mit.edu/chord/ 278 279 -- 280 281 References 282 283 http://www.isthe.com/chongo/tech/comp/fnv/ 284 http://www.azillionmonkeys.com/qed/hash.html 285 http://www.azillionmonkeys.com/qed/hash.c 286 http://www.digitalmars.com/d/2.0/htomodule.html 287 288 http://www.team5150.com/~andrew/blog/2007/03/breaking_superfasthash.html 289 http://www.team5150.com/~andrew/blog/2007/03/when_bad_hashing_means_good_caching.html 290 http://www.azillionmonkeys.com/qed/hash.html 291 292 *******************************************************************************/ 293 294 public class Fnv1Generic ( bool FNV1A = false, T = hash_t ) : FnvDigest 295 { 296 /************************************************************************** 297 298 DigestType type alias 299 300 **************************************************************************/ 301 302 mixin Fnv1Const!(T); 303 304 /************************************************************************** 305 306 Binary digest length and hexadecimal digest string length constants 307 308 **************************************************************************/ 309 310 public static immutable DIGEST_LENGTH = DigestType.sizeof; 311 public static immutable HEXDGT_LENGTH = DIGEST_LENGTH * 2; 312 313 public alias char[HEXDGT_LENGTH] HexDigest; 314 315 /************************************************************************** 316 317 This alias for chainable methods 318 319 **************************************************************************/ 320 321 public alias typeof (this) This; 322 323 /************************************************************************** 324 325 Endianness aware integer to byte array converter 326 327 Usage: 328 329 --- 330 331 Fnv32.BinConvert bc; 332 333 ubyte[] binstr = bc(0xAFFE4711); 334 335 // binstr now is [0xAF, 0xFE, 0x47, 0x11] 336 337 --- 338 339 **************************************************************************/ 340 341 public union BinConvert 342 { 343 public alias ubyte[DIGEST_LENGTH] BinString; 344 345 /* members */ 346 347 public BinString array; 348 349 public DigestType value; 350 351 /* cast "value" from integer type "DigestType" to binary string type "BinString" 352 considering machine byte order (endianness) */ 353 354 public ubyte[] opCall ( DigestType value ) 355 { 356 this.value = value; 357 358 version (LittleEndian) toBigEnd(array); 359 360 return array.dup; 361 } 362 }; 363 364 365 /************************************************************************** 366 367 class properties 368 369 **************************************************************************/ 370 371 private DigestType digest = this.INIT; 372 373 374 /************************************************************************** 375 376 Tango DigestType class methods 377 378 **************************************************************************/ 379 380 381 /************************************************************************** 382 383 Processes data 384 385 Remarks: 386 Updates the hash algorithm state with new data 387 388 **************************************************************************/ 389 390 public override This update ( const(void)[] data ) 391 { 392 this.digest = this.fnv1(data, this.digest); 393 394 return this; 395 } 396 397 398 /************************************************************************** 399 400 Computes the digest and resets the state 401 402 Params: 403 buffer = a buffer can be supplied for the digest to be 404 written to 405 406 Remarks: 407 This method is endianness-aware: The returned array has always the 408 least-order byte at byte [0] (big endian). 409 410 If the buffer is not large enough to hold the 411 digest, a new buffer is allocated and returned. 412 The algorithm state is always reset after a call to 413 binaryDigest. Use the digestSize method to find out how 414 large the buffer has to be. 415 416 ***************************************************************************/ 417 418 public override ubyte[] binaryDigest( ubyte[] buffer = null ) 419 { 420 scope(exit) this.reset(); 421 422 BinConvert bc; 423 424 bc(this.digest); 425 426 if ( buffer ) 427 { 428 buffer.length = this.digestSize(); 429 430 foreach (i, d; bc.array) 431 { 432 buffer[i] = d; 433 } 434 } 435 436 return buffer? buffer: bc.array.dup; 437 } 438 439 440 /************************************************************************** 441 442 Returns the size in bytes of the digest 443 444 Returns: 445 the size of the digest in bytes 446 447 Remarks: 448 Returns the size of the digest. 449 450 ***************************************************************************/ 451 452 public override uint digestSize ( ) 453 { 454 return this.DIGEST_LENGTH; 455 } 456 457 458 /************************************************************************** 459 460 extension class methods (in addition to the DigestType standard methods) 461 462 **************************************************************************/ 463 464 465 /************************************************************************** 466 467 Resets the state 468 469 Returns: 470 this instance 471 472 ***************************************************************************/ 473 474 public This reset ( ) 475 { 476 this.digest = this.INIT; 477 478 return this; 479 } 480 481 482 /************************************************************************** 483 484 Simply returns the digest 485 486 Returns: 487 digest 488 489 **************************************************************************/ 490 491 public DigestType getDigest ( ) 492 { 493 return this.digest; 494 } 495 496 497 /************************************************************************** 498 499 Simply returns the digest as an ulong independently of the digest size 500 and reset the internal state. 501 502 Returns: 503 digest 504 505 **************************************************************************/ 506 507 public override ulong ulongDigest ( ) 508 { 509 ulong d = this.digest; 510 this.reset(); 511 return d; 512 } 513 514 515 /************************************************************************** 516 517 Core methods 518 519 **************************************************************************/ 520 521 522 523 /************************************************************************** 524 525 Calculates a FNV1/FNV1a digest from data. data are processed in 526 octet/byte-wise manner. 527 528 Usage: 529 530 --- 531 532 import ocean.io.digest.Fnv; 533 534 auto data = "sociomantic"; 535 536 uint digest32 = Fnv32.fnv1(data); 537 ulong digest64 = Fnv64.fnv1(data); 538 539 --- 540 541 Params: 542 data = data to digest 543 digest = initial digest; defaults to the magic 32 bit or 64 bit 544 initial value, according to DigestType 545 546 Returns: 547 resulting digest 548 549 **************************************************************************/ 550 551 public static DigestType fnv1 ( U ) ( U data, DigestType digest = INIT ) 552 { 553 const(ubyte)[] data_; 554 555 static if (is (Unqual!(U) : ubyte[])) 556 { 557 data_ = data; 558 } 559 else static if (is (U V : V[])) 560 { 561 static if (V.sizeof == 1) 562 { 563 data_ = cast(const(ubyte)[])data; 564 } 565 else 566 { 567 data_ = (cast(const(ubyte)*)data.ptr)[0 .. data.length * V.sizeof]; 568 } 569 } 570 else 571 { 572 data_ = cast(const(ubyte)[])((cast(const(void)*)&data)[0 .. data.sizeof]); 573 } 574 575 foreach (d; data_) 576 { 577 digest = fnv1_core(d, digest); 578 } 579 580 return digest; 581 } 582 583 public alias fnv1 opCall; 584 585 586 /************************************************************************** 587 588 Calculates a FNV1/FNV1a digest from data and generates a hexdecimal 589 string representation of the digest. data are processed in 590 octet/byte-wise manner. 591 592 Usage: 593 594 --- 595 596 import ocean.io.digest.Fnv; 597 598 Fnv32.HexDigest digest32; 599 Fnv64.HexDigest digest64; 600 601 auto data = "sociomantic"; 602 603 digest32 = Fnv32.fnv1(data, digest32); 604 digest64 = Fnv64.fnv1(data, digest32); 605 606 --- 607 608 Params: 609 data = data to digest 610 hexdgst = string buffer 611 digest = initial digest; defaults to the magic 32 bit or 64 bit 612 initial value, according to DigestType 613 614 Returns: 615 hexdecimal string representation of resulting digest 616 617 **************************************************************************/ 618 619 public static char[] fnv1_hex ( U ) ( U data, char[] hexdgst, DigestType digest = INIT ) 620 { 621 digest = fnv1(data, digest); 622 623 foreach_reverse (ref h; hexdgst) 624 { 625 h = "0123456789abcdef"[digest & 0xF]; 626 627 digest >>= 4; 628 } 629 630 return hexdgst; 631 } 632 633 634 /************************************************************************** 635 636 FNV1/FNV1a core; calculates a digest of one octet d 637 638 Params: 639 d = data to digest 640 digest = initial digest 641 642 Returns: 643 resulting digest 644 645 **************************************************************************/ 646 647 public static DigestType fnv1_core ( ubyte d, DigestType digest ) 648 { 649 static if (FNV1A) 650 { 651 return (digest ^ d) * PRIME; 652 } 653 else 654 { 655 return (digest * PRIME) ^ d; 656 } 657 } 658 659 660 /*************************************************************************** 661 662 Creates a combined hash of all the provided parameters. 663 The previous hashed value is used as the initial state for the next. 664 665 Params: 666 Vals = Tuple of value types, inferred. 667 vals = the values to be used for hashing 668 669 Returns: 670 returns the combined hash 671 672 ***************************************************************************/ 673 674 public static hash_t combined ( Vals... ) ( Vals vals ) 675 { 676 hash_t hash = INIT; 677 678 foreach (val; vals) 679 { 680 hash = fnv1(val, hash); 681 } 682 683 return hash; 684 } 685 } 686 687 688 /************************************************************************** 689 690 unit test 691 692 693 Test data for FNV1/FNV1a hash algorithm 694 695 Data taken from Landon Curt Noll's FNV test program source code: 696 697 http://www.isthe.com/chongo/src/fnv/test_fnv.c 698 699 found at his FNV web page: 700 701 http://www.isthe.com/chongo/tech/comp/fnv/ 702 703 704 The original code was released as public domain by chongo <Landon Curt 705 Noll>: 706 http://web.archive.org/web/20101105131957/http://www.isthe.com/chongo/src/fnv/test_fnv.c 707 708 C to D port by David Eckardt, dunnhumby Germany GmbH, October 2009 709 710 **************************************************************************/ 711 712 713 version (unittest) 714 { 715 // Uncomment the next line to see UnitTest output 716 // version = UnitTestVerbose; 717 718 private istring errmsg ( istring func, istring str, bool is_text ) 719 { 720 auto errmsg = "unit test failed for " ~ func; 721 722 if (is_text) 723 { 724 errmsg ~= ": \"" ~ str ~ "\""; 725 } 726 727 return errmsg; 728 } 729 } 730 731 unittest 732 { 733 struct TestData 734 { 735 /* 736 * 32-bit FNV1 digests of "string" below as integer, binary data string 737 * and hexadecimal text string 738 */ 739 uint fnv1_32; 740 ubyte[] fnv1_32_bin; 741 istring fnv1_32_hex; 742 743 /* 744 * 32-bit FNV1a digests of "string" below as integer, binary data string 745 * and hexadecimal text string 746 */ 747 uint fnv1a_32; 748 ubyte[] fnv1a_32_bin; 749 istring fnv1a_32_hex; 750 751 /* 752 * 64-bit FNV1 digests of "string" below as integer, binary data string 753 * and hexadecimal text string 754 */ 755 ulong fnv1_64; 756 ubyte[] fnv1_64_bin; 757 istring fnv1_64_hex; 758 759 /* 760 * 64-bit FNV1a digests of "string" below as integer, binary data string 761 * and hexadecimal text string 762 */ 763 ulong fnv1a_64; 764 ubyte[] fnv1a_64_bin; 765 istring fnv1a_64_hex; 766 767 /* 768 * is_text == true indicates that the content of "string" is safe to 769 * write to a text output (text file, console...). 770 */ 771 bool is_text; 772 773 // string of which the digests above are computed from 774 istring str; 775 } 776 777 static immutable TestData[] testdata = 778 [ 779 {0xc5f1d7e9, [0xc5, 0xf1, 0xd7, 0xe9], "c5f1d7e9", 0x512b2851, [0x51, 0x2b, 0x28, 0x51], "512b2851", 0x43c94e2c8b277509, [0x43, 0xc9, 0x4e, 0x2c, 0x8b, 0x27, 0x75, 0x09], "43c94e2c8b277509", 0x33b96c3cd65b5f71, [0x33, 0xb9, 0x6c, 0x3c, 0xd6, 0x5b, 0x5f, 0x71], "33b96c3cd65b5f71", true, "391581216093391581216093391581216093391581216093391581216093391581216093391581216093391581216093391581216093391581216093"}, 780 {0x32c1f439, [0x32, 0xc1, 0xf4, 0x39], "32c1f439", 0x76823999, [0x76, 0x82, 0x39, 0x99], "76823999", 0x3cbfd4e4ea670359, [0x3c, 0xbf, 0xd4, 0xe4, 0xea, 0x67, 0x03, 0x59], "3cbfd4e4ea670359", 0xd845097780602bb9, [0xd8, 0x45, 0x09, 0x77, 0x80, 0x60, 0x2b, 0xb9], "d845097780602bb9", true, "391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1391581*2^216093-1"}, 781 {0x7fd3eb7d, [0x7f, 0xd3, 0xeb, 0x7d], "7fd3eb7d", 0xc0586935, [0xc0, 0x58, 0x69, 0x35], "c0586935", 0xc05887810f4d019d, [0xc0, 0x58, 0x87, 0x81, 0x0f, 0x4d, 0x01, 0x9d], "c05887810f4d019d", 0x84d47645d02da3d5, [0x84, 0xd4, 0x76, 0x45, 0xd0, 0x2d, 0xa3, 0xd5], "84d47645d02da3d5", false, "\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81\x05\xf9\x9d\x03\x4c\x81"}, 782 {0x81597da5, [0x81, 0x59, 0x7d, 0xa5], "81597da5", 0xf3415c85, [0xf3, 0x41, 0x5c, 0x85], "f3415c85", 0x14468ff93ac22dc5, [0x14, 0x46, 0x8f, 0xf9, 0x3a, 0xc2, 0x2d, 0xc5], "14468ff93ac22dc5", 0x83544f33b58773a5, [0x83, 0x54, 0x4f, 0x33, 0xb5, 0x87, 0x73, 0xa5], "83544f33b58773a5", false, "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210"}, 783 {0x05eb7a25, [0x05, 0xeb, 0x7a, 0x25], "05eb7a25", 0x0ae4ff65, [0x0a, 0xe4, 0xff, 0x65], "0ae4ff65", 0xebed699589d99c05, [0xeb, 0xed, 0x69, 0x95, 0x89, 0xd9, 0x9c, 0x05], "ebed699589d99c05", 0x9175cbb2160836c5, [0x91, 0x75, 0xcb, 0xb2, 0x16, 0x08, 0x36, 0xc5], "9175cbb2160836c5", false, "\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10\xfe\xdc\xba\x98\x76\x54\x32\x10"}, 784 {0x9c0fa1b5, [0x9c, 0x0f, 0xa1, 0xb5], "9c0fa1b5", 0x58b79725, [0x58, 0xb7, 0x97, 0x25], "58b79725", 0x6d99f6df321ca5d5, [0x6d, 0x99, 0xf6, 0xdf, 0x32, 0x1c, 0xa5, 0xd5], "6d99f6df321ca5d5", 0xc71b3bc175e72bc5, [0xc7, 0x1b, 0x3b, 0xc1, 0x75, 0xe7, 0x2b, 0xc5], "c71b3bc175e72bc5", true, "EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301EFCDAB8967452301"}, 785 {0x53ccb1c5, [0x53, 0xcc, 0xb1, 0xc5], "53ccb1c5", 0xdea43aa5, [0xde, 0xa4, 0x3a, 0xa5], "dea43aa5", 0x0cd410d08c36d625, [0x0c, 0xd4, 0x10, 0xd0, 0x8c, 0x36, 0xd6, 0x25], "0cd410d08c36d625", 0x636806ac222ec985, [0x63, 0x68, 0x06, 0xac, 0x22, 0x2e, 0xc9, 0x85], "636806ac222ec985", false, "\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01\xef\xcd\xab\x89\x67\x45\x23\x01"}, 786 {0xfabece15, [0xfa, 0xbe, 0xce, 0x15], "fabece15", 0x2bb3be35, [0x2b, 0xb3, 0xbe, 0x35], "2bb3be35", 0xef1b2a2c86831d35, [0xef, 0x1b, 0x2a, 0x2c, 0x86, 0x83, 0x1d, 0x35], "ef1b2a2c86831d35", 0xb6ef0e6950f52ed5, [0xb6, 0xef, 0x0e, 0x69, 0x50, 0xf5, 0x2e, 0xd5], "b6ef0e6950f52ed5", true, "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"}, 787 {0x4ad745a5, [0x4a, 0xd7, 0x45, 0xa5], "4ad745a5", 0xea777a45, [0xea, 0x77, 0x7a, 0x45], "ea777a45", 0x3b349c4d69ee5f05, [0x3b, 0x34, 0x9c, 0x4d, 0x69, 0xee, 0x5f, 0x05], "3b349c4d69ee5f05", 0xead3d8a0f3dfdaa5, [0xea, 0xd3, 0xd8, 0xa0, 0xf3, 0xdf, 0xda, 0xa5], "ead3d8a0f3dfdaa5", false, "\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef"}, 788 {0xe5bdc495, [0xe5, 0xbd, 0xc4, 0x95], "e5bdc495", 0x8f21c305, [0x8f, 0x21, 0xc3, 0x05], "8f21c305", 0x55248ce88f45f035, [0x55, 0x24, 0x8c, 0xe8, 0x8f, 0x45, 0xf0, 0x35], "55248ce88f45f035", 0x922908fe9a861ba5, [0x92, 0x29, 0x08, 0xfe, 0x9a, 0x86, 0x1b, 0xa5], "922908fe9a861ba5", true, "1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE1032547698BADCFE"}, 789 {0x23b3c0a5, [0x23, 0xb3, 0xc0, 0xa5], "23b3c0a5", 0x5c9d0865, [0x5c, 0x9d, 0x08, 0x65], "5c9d0865", 0xaa69ca6a18a4c885, [0xaa, 0x69, 0xca, 0x6a, 0x18, 0xa4, 0xc8, 0x85], "aa69ca6a18a4c885", 0x6d4821de275fd5c5, [0x6d, 0x48, 0x21, 0xde, 0x27, 0x5f, 0xd5, 0xc5], "6d4821de275fd5c5", false, "\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe\x10\x32\x54\x76\x98\xba\xdc\xfe"}, 790 {0xfa823dd5, [0xfa, 0x82, 0x3d, 0xd5], "fa823dd5", 0xfa823dd5, [0xfa, 0x82, 0x3d, 0xd5], "fa823dd5", 0x1fe3fce62bd816b5, [0x1f, 0xe3, 0xfc, 0xe6, 0x2b, 0xd8, 0x16, 0xb5], "1fe3fce62bd816b5", 0x1fe3fce62bd816b5, [0x1f, 0xe3, 0xfc, 0xe6, 0x2b, 0xd8, 0x16, 0xb5], "1fe3fce62bd816b5", false, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}, 791 {0x0c6c58b9, [0x0c, 0x6c, 0x58, 0xb9], "0c6c58b9", 0x21a27271, [0x21, 0xa2, 0x72, 0x71], "21a27271", 0x0289a488a8df69d9, [0x02, 0x89, 0xa4, 0x88, 0xa8, 0xdf, 0x69, 0xd9], "0289a488a8df69d9", 0xc23e9fccd6f70591, [0xc2, 0x3e, 0x9f, 0xcc, 0xd6, 0xf7, 0x05, 0x91], "c23e9fccd6f70591", false, "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07"}, 792 {0xe2dbccd5, [0xe2, 0xdb, 0xcc, 0xd5], "e2dbccd5", 0x83c5c6d5, [0x83, 0xc5, 0xc6, 0xd5], "83c5c6d5", 0x15e96e1613df98b5, [0x15, 0xe9, 0x6e, 0x16, 0x13, 0xdf, 0x98, 0xb5], "15e96e1613df98b5", 0xc1af12bdfe16b5b5, [0xc1, 0xaf, 0x12, 0xbd, 0xfe, 0x16, 0xb5, 0xb5], "c1af12bdfe16b5b5", true, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"}, 793 {0xdb7f50f9, [0xdb, 0x7f, 0x50, 0xf9], "db7f50f9", 0x813b0881, [0x81, 0x3b, 0x08, 0x81], "813b0881", 0xe6be57375ad89b99, [0xe6, 0xbe, 0x57, 0x37, 0x5a, 0xd8, 0x9b, 0x99], "e6be57375ad89b99", 0x39e9f18f2f85e221, [0x39, 0xe9, 0xf1, 0x8f, 0x2f, 0x85, 0xe2, 0x21], "39e9f18f2f85e221", false, "\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f"} 794 ]; 795 796 scope Fnv1a32 fnv1a32 = new Fnv1a32; 797 scope Fnv1a64 fnv1a64 = new Fnv1a64; 798 799 foreach (tdat; testdata) 800 { 801 /********************************************************************** 802 803 core methods test 804 805 **********************************************************************/ 806 807 test (Fnv1a32.fnv1(tdat.str) == tdat.fnv1a_32, errmsg("Fnv1a32.fnv1", tdat.str, tdat.is_text)); 808 test (Fnv1a64.fnv1(tdat.str) == tdat.fnv1a_64, errmsg("Fnv1a64.fnv1", tdat.str, tdat.is_text)); 809 810 /********************************************************************** 811 812 class methods test 813 814 **********************************************************************/ 815 816 test (fnv1a32.update(tdat.str).hexDigest == tdat.fnv1a_32_hex, errmsg("Fnv1a32.hexDigest", tdat.str, tdat.is_text)); 817 test (fnv1a64.update(tdat.str).hexDigest == tdat.fnv1a_64_hex, errmsg("Fnv1a64.hexDigest", tdat.str, tdat.is_text)); 818 } 819 820 821 test ( StaticFnv1a32!("myString") == Fnv1a32("myString"[]), "CompileTime Fnv1a32 failed"); 822 test ( StaticFnv1a32!("TEST") == Fnv1a32("TEST"[]), "CompileTime Fnv1a32 failed"); 823 824 825 istring d1 = "ABC"; 826 int d2 = 123; 827 ulong d3 = 12354; 828 829 auto chash = Fnv1a.combined(d1, d2, d3); 830 831 auto mhash = Fnv1a(d3, Fnv1a(d2, Fnv1a(d1))); 832 833 test (chash == mhash, "Combined hash failed"); 834 }