1 /** 2 Adler-32 implementation. This module conforms to the APIs defined in std.digest.digest. 3 */ 4 module digestx.adler; 5 6 7 public import std.digest.digest; 8 9 10 struct Adler32 11 { 12 /// Initializes the digest calculation. 13 void start() @safe pure nothrow @nogc 14 { 15 _a = 1; 16 _b = 0; 17 _tlen = moduloInterval; 18 } 19 20 /// Feeds the digest with data. 21 void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc 22 { 23 foreach (immutable ubyte i; data) 24 { 25 _a += i; 26 _b += _a; 27 28 --_tlen; 29 if (_tlen == 0) 30 { 31 _a %= 65521; 32 _b %= 65521; 33 _tlen = moduloInterval; 34 } 35 } 36 37 if (_tlen != moduloInterval) 38 { 39 _a %= 65521; 40 _b %= 65521; 41 } 42 } 43 44 /// Returns the finished Adler-32 digest. This also calls start to reset the internal state. 45 ubyte[4] finish() @trusted pure nothrow @nogc 46 { 47 import std.bitmanip : nativeToBigEndian; 48 49 auto a = _a, b = _b; 50 51 start(); 52 53 static if (__VERSION__ < 2067) 54 { 55 // Phobos bug: std.bitmanip.nativeToBigEndian is not annotated with @nogc 56 return (cast(ubyte[4] function(uint) @safe pure nothrow @nogc)&nativeToBigEndian!uint) 57 ((b << 16) | a); 58 } 59 else 60 { 61 return nativeToBigEndian((b << 16) | a); 62 } 63 } 64 65 private: 66 67 uint _a = void, _b = void; 68 uint _tlen = void; 69 70 enum moduloInterval = 5552; 71 } 72 73 //Convenience alias for $(D digest) function in std.digest.digest using the Adler32 implementation. 74 auto adler32Of(T...)(T data) 75 { 76 return digest!(Adler32, T)(data); 77 } 78 79 /// OOP API for Adler32. 80 alias Adler32Digest = WrapperDigest!Adler32; 81 82 /// 83 unittest 84 { 85 Adler32 adler; 86 adler.start(); 87 adler.put(cast(ubyte[])"abc"); 88 assert(adler.finish() == x"024d0127"); 89 adler.start(); 90 adler.put(cast(ubyte[])"def"); 91 assert(adler.finish() == x"025F0130"); 92 93 assert(adler32Of("abc") == x"024d0127"); 94 } 95 96 @safe pure nothrow @nogc 97 unittest 98 { 99 static assert(isDigest!Adler32); 100 101 assert(adler32Of("abc") == x"024d0127"); 102 assert(adler32Of("abcdefghijklmnopqrstuvwxyz") == x"90860B20"); 103 } 104 105 pure nothrow @nogc 106 unittest 107 { 108 import std.range : repeat; 109 assert(adler32Of(repeat('a', 1000000)) == x"15D870F9"); 110 } 111 112 /// 113 unittest 114 { 115 auto adler = new Adler32Digest; 116 assert(adler.digest("abc") == x"024d0127"); 117 }