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