hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 098920432e447c4e288aab3b56962bb21cc529ea
parent 002cdf70cf43e0b8e8452187afe6d3e3f606fd9d
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Mon, 29 Mar 2021 17:50:44 -0400

hash::adler32: new module

Diffstat:
Ahash/adler32/adler32.ha | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mscripts/gen-stdlib | 8++++++++
Mstdlib.mk | 26++++++++++++++++++++++++++
3 files changed, 119 insertions(+), 0 deletions(-)

diff --git a/hash/adler32/adler32.ha b/hash/adler32/adler32.ha @@ -0,0 +1,85 @@ +// Implements the Adler-32 checksum algorithm. It is a non-cryptographic +// checksum. + +use endian; +use hash; +use io; +use strings; + +type state = struct { + hash: hash::hash, + a: u32, + b: u32, +}; + +// Creates a [hash::hash] which computes the Adler-32 checksum algorithm. +export fn adler32() *hash::hash = alloc(state { + hash = hash::hash { + stream = io::stream { + writer = &write, + closer = &close, + ... + }, + sum = &sum, + reset = &reset, + sz = 4, + }, + a = 1, + b = 0, +}): *hash::hash; + +fn close(s: *io::stream) void = free(s); + +fn write(s: *io::stream, buf: const []u8) (size | io::error) = { + let s = s: *state; + for (let i = 0z; i < len(buf); i += 1) { + s.a = (s.a + buf[i]) % 65521; + s.b = (s.b + s.a) % 65521; + }; + return len(buf); +}; + +fn reset(h: *hash::hash) void = { + let h = h: *state; + h.a = 1; + h.b = 0; +}; + +fn sum(h: *hash::hash) []u8 = { + let h = h: *state; + let buf: [4]u8 = [0...]; + // RFC 1950 specifies that Adler-32 checksums are stored in network + // order. + endian::beputu32(buf, (h.b << 16) | h.a); + return alloc(buf); +}; + +export fn sum32(h: *hash::hash) u32 = { + assert(h.reset == &reset); + let h = h: *state; + return h.b << 16 | h.a; +}; + +@test fn adler32() void = { + const vectors: [](str, u32) = [ + ("", 1), + ("hello world", 436929629), + ("Hare is a cool language", 1578567727), + ("'UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things' - Doug Gwyn", 2140876731), + ("'Life is too short to run proprietary software' - Bdale Garbee", 3135706652), + ("'The central enemy of reliability is complexity.' - Geer et al", 3170309588), + ("'A language that doesn’t have everything is actually easier to program in than some that do.' - Dennis Ritchie", 1148528899), + + ]; + let hash = adler32(); + defer hash::close(hash); + for (let i = 0z; i < len(vectors); i += 1) { + let vec = vectors[i]; + hash::reset(hash); + hash::write(hash, strings::toutf8(vec.0)); + let s = hash::sum(hash); + defer free(s); + assert(endian::begetu32(s) == vec.1); + assert(sum32(hash) == vec.1); + }; +}; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -346,6 +346,13 @@ hash() { gen_ssa hash io } +hash_adler32() { + printf '# hash::adler32\n' + gen_srcs hash::adler32 \ + adler32.ha + gen_ssa hash::adler32 endian hash io strings +} + hash_fnv() { printf '# hash::fnv\n' gen_srcs hash::fnv \ @@ -603,6 +610,7 @@ hare_module hare_parse hare_unparse hash +hash_adler32 hash_fnv io linux diff --git a/stdlib.mk b/stdlib.mk @@ -135,6 +135,9 @@ hare_stdlib_deps+=$(stdlib_hare_unparse) stdlib_hash=$(HARECACHE)/hash/hash.o hare_stdlib_deps+=$(stdlib_hash) +stdlib_hash_adler32=$(HARECACHE)/hash/adler32/hash_adler32.o +hare_stdlib_deps+=$(stdlib_hash_adler32) + stdlib_hash_fnv=$(HARECACHE)/hash/fnv/hash_fnv.o hare_stdlib_deps+=$(stdlib_hash_fnv) @@ -455,6 +458,16 @@ $(HARECACHE)/hash/hash.ssa: $(stdlib_hash_srcs) $(stdlib_rt) $(stdlib_io) @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhash \ -t$(HARECACHE)/hash/hash.td $(stdlib_hash_srcs) +# hash::adler32 +stdlib_hash_adler32_srcs= \ + $(STDLIB)/hash/adler32/adler32.ha + +$(HARECACHE)/hash/adler32/hash_adler32.ssa: $(stdlib_hash_adler32_srcs) $(stdlib_rt) $(stdlib_endian) $(stdlib_hash) $(stdlib_io) $(stdlib_strings) + @printf 'HAREC \t$@\n' + @mkdir -p $(HARECACHE)/hash/adler32 + @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhash::adler32 \ + -t$(HARECACHE)/hash/adler32/hash_adler32.td $(stdlib_hash_adler32_srcs) + # hash::fnv stdlib_hash_fnv_srcs= \ $(STDLIB)/hash/fnv/fnv.ha @@ -839,6 +852,9 @@ hare_testlib_deps+=$(testlib_hare_unparse) testlib_hash=$(TESTCACHE)/hash/hash.o hare_testlib_deps+=$(testlib_hash) +testlib_hash_adler32=$(TESTCACHE)/hash/adler32/hash_adler32.o +hare_testlib_deps+=$(testlib_hash_adler32) + testlib_hash_fnv=$(TESTCACHE)/hash/fnv/hash_fnv.o hare_testlib_deps+=$(testlib_hash_fnv) @@ -1164,6 +1180,16 @@ $(TESTCACHE)/hash/hash.ssa: $(testlib_hash_srcs) $(testlib_rt) $(testlib_io) @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhash \ -t$(TESTCACHE)/hash/hash.td $(testlib_hash_srcs) +# hash::adler32 +testlib_hash_adler32_srcs= \ + $(STDLIB)/hash/adler32/adler32.ha + +$(TESTCACHE)/hash/adler32/hash_adler32.ssa: $(testlib_hash_adler32_srcs) $(testlib_rt) $(testlib_endian) $(testlib_hash) $(testlib_io) $(testlib_strings) + @printf 'HAREC \t$@\n' + @mkdir -p $(TESTCACHE)/hash/adler32 + @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhash::adler32 \ + -t$(TESTCACHE)/hash/adler32/hash_adler32.td $(testlib_hash_adler32_srcs) + # hash::fnv testlib_hash_fnv_srcs= \ $(STDLIB)/hash/fnv/fnv.ha