My working unpac space for OCaml projects in development
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add xxhash library implementation and tests

- Pure OCaml xxHash-64 implementation with one-shot and streaming APIs
- 21 tests covering consistency, boundaries, streaming, and properties
- Vendored C reference from github.com/Cyan4973/xxHash
- STATUS.md documenting work needed for reference test suite integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+727
+112
vendor/opam/ocaml-xxhash/STATUS.md
··· 1 + # ocaml-xxhash Status 2 + 3 + Pure OCaml implementation of xxHash-64 non-cryptographic hash algorithm. 4 + 5 + ## Current Status: Working 6 + 7 + The library is functional with: 8 + - One-shot hashing API (`hash64`, `hash64_string`, `hash32`, `hash32_string`) 9 + - Streaming API (`create_state`, `update`, `finalize`) 10 + - State management (`reset`, `copy_state`) 11 + - 21 tests passing (consistency, boundaries, streaming, properties) 12 + 13 + ## Vendored Reference 14 + 15 + The C reference implementation is vendored at: 16 + ``` 17 + vendor/git/xxHash/ 18 + ``` 19 + 20 + This is the official xxHash repository by Yann Collet (https://github.com/Cyan4973/xxHash). 21 + 22 + ## Work Needed 23 + 24 + ### 1. Validate Against Reference Test Suite 25 + 26 + The C reference includes comprehensive test vectors in: 27 + ``` 28 + vendor/git/xxHash/tests/sanity_test_vectors.h 29 + ``` 30 + 31 + The test data uses a deterministic pseudorandom buffer: 32 + ```c 33 + PRIME32 = 2654435761 34 + PRIME64 = 11400714785074694797 35 + 36 + void fillTestBuffer(buffer, len) { 37 + byteGen = PRIME32 38 + for i = 0 to len: 39 + buffer[i] = byteGen >> 56 40 + byteGen *= PRIME64 41 + } 42 + ``` 43 + 44 + Test vectors are of the form `{length, seed, expected_hash}`: 45 + - XXH64 vectors: `XSUM_XXH64_testdata[]` (line 8356+) 46 + - Over 4000 test cases covering lengths 0-4096+ bytes 47 + 48 + **Task**: Generate the same test buffer in OCaml and verify against these vectors. 49 + 50 + ### 2. Add Reference Test Integration 51 + 52 + Create `test/test_reference.ml` that: 53 + 1. Generates the pseudorandom test buffer matching the C implementation 54 + 2. Runs through `XSUM_XXH64_testdata` test vectors 55 + 3. Compares our implementation against expected hashes 56 + 57 + Example approach: 58 + ```ocaml 59 + let prime32 = 2654435761L (* unsigned 32-bit *) 60 + let prime64 = 0x9E3779B97F4A7C15L (* 11400714785074694797 as signed *) 61 + 62 + let fill_test_buffer len = 63 + let buf = Bytes.create len in 64 + let rec loop i gen = 65 + if i >= len then buf 66 + else begin 67 + Bytes.set_uint8 buf i (Int64.(to_int (shift_right_logical gen 56))); 68 + loop (i + 1) Int64.(mul gen prime64) 69 + end 70 + in 71 + loop 0 (Int64.of_int32 (Int32.of_int 2654435761)) 72 + ``` 73 + 74 + ### 3. Consider xxHash-32 Native Implementation 75 + 76 + Currently `hash32` returns lower 32 bits of xxHash-64. The reference includes 77 + a native XXH32 algorithm that's faster for 32-bit platforms. Consider adding: 78 + - `Xxhash.xxh32` - native 32-bit algorithm 79 + - Keep `hash32` as alias for lower bits of xxh64 (zstd compatibility) 80 + 81 + ### 4. Consider xxHash-3 (XXH3) 82 + 83 + The latest xxHash version includes XXH3 with better performance: 84 + - XXH3_64bits - faster than XXH64 on modern CPUs 85 + - XXH3_128bits - 128-bit hash variant 86 + - Uses hardware SIMD when available 87 + 88 + For pure OCaml, XXH64 is sufficient but XXH3 could be added if needed. 89 + 90 + ## Files 91 + 92 + ``` 93 + src/ 94 + xxhash.ml - Implementation 95 + xxhash.mli - Interface 96 + dune - Build config 97 + 98 + test/ 99 + test_xxhash.ml - Current tests (consistency, properties) 100 + dune - Test config 101 + 102 + vendor/git/xxHash/ - C reference implementation 103 + tests/ 104 + sanity_test.c - Test runner 105 + sanity_test_vectors.h - 4.5MB of test vectors 106 + ``` 107 + 108 + ## References 109 + 110 + - [xxHash GitHub](https://github.com/Cyan4973/xxHash) 111 + - [xxHash specification](https://github.com/Cyan4973/xxHash/blob/dev/doc/xxhash_spec.md) 112 + - [RFC for zstd (uses xxHash)](https://datatracker.ietf.org/doc/html/rfc8878)
+3
vendor/opam/ocaml-xxhash/src/dune
··· 1 + (library 2 + (name xxhash) 3 + (public_name xxhash))
+264
vendor/opam/ocaml-xxhash/src/xxhash.ml
··· 1 + (** xxHash-64 - Pure OCaml implementation. 2 + 3 + This implements the xxHash64 algorithm designed by Yann Collet. 4 + xxHash is an extremely fast non-cryptographic hash algorithm with 5 + excellent distribution properties. *) 6 + 7 + (* Constants *) 8 + let prime64_1 = 0x9E3779B185EBCA87L 9 + let prime64_2 = 0xC2B2AE3D27D4EB4FL 10 + let prime64_3 = 0x165667B19E3779F9L 11 + let prime64_4 = 0x85EBCA77C2B2AE63L 12 + let prime64_5 = 0x27D4EB2F165667C5L 13 + 14 + (* Helper functions *) 15 + let[@inline] rotl64 x r = 16 + Int64.(logor (shift_left x r) (shift_right_logical x (64 - r))) 17 + 18 + let[@inline] mix1 acc v = 19 + let open Int64 in 20 + let acc = add acc (mul v prime64_2) in 21 + let acc = rotl64 acc 31 in 22 + mul acc prime64_1 23 + 24 + let[@inline] mix2 acc v = 25 + let open Int64 in 26 + let v = mul v prime64_2 in 27 + let v = rotl64 v 31 in 28 + let v = mul v prime64_1 in 29 + let acc = logxor acc v in 30 + add (mul acc prime64_1) prime64_4 31 + 32 + let[@inline] avalanche h = 33 + let open Int64 in 34 + let h = logxor h (shift_right_logical h 33) in 35 + let h = mul h prime64_2 in 36 + let h = logxor h (shift_right_logical h 29) in 37 + let h = mul h prime64_3 in 38 + logxor h (shift_right_logical h 32) 39 + 40 + (** Compute xxHash-64 of bytes with given seed *) 41 + let hash64 ?(seed=0L) src ~pos ~len = 42 + let open Int64 in 43 + let end_pos = pos + len in 44 + 45 + let h = ref ( 46 + if len >= 32 then begin 47 + (* Initialize accumulators *) 48 + let v1 = ref (add (add seed prime64_1) prime64_2) in 49 + let v2 = ref (add seed prime64_2) in 50 + let v3 = ref seed in 51 + let v4 = ref (sub seed prime64_1) in 52 + 53 + (* Process 32-byte blocks *) 54 + let p = ref pos in 55 + while !p + 32 <= end_pos do 56 + v1 := mix1 !v1 (Bytes.get_int64_le src !p); 57 + v2 := mix1 !v2 (Bytes.get_int64_le src (!p + 8)); 58 + v3 := mix1 !v3 (Bytes.get_int64_le src (!p + 16)); 59 + v4 := mix1 !v4 (Bytes.get_int64_le src (!p + 24)); 60 + p := !p + 32 61 + done; 62 + 63 + (* Merge accumulators *) 64 + let h = add 65 + (add (rotl64 !v1 1) (rotl64 !v2 7)) 66 + (add (rotl64 !v3 12) (rotl64 !v4 18)) in 67 + let h = mix2 h !v1 in 68 + let h = mix2 h !v2 in 69 + let h = mix2 h !v3 in 70 + mix2 h !v4 71 + end else 72 + add seed prime64_5 73 + ) in 74 + 75 + h := add !h (of_int len); 76 + 77 + (* Process remaining 8-byte chunks *) 78 + let p = ref (if len >= 32 then pos + (len / 32) * 32 else pos) in 79 + while !p + 8 <= end_pos do 80 + let k = Bytes.get_int64_le src !p in 81 + let k = mul k prime64_2 in 82 + let k = rotl64 k 31 in 83 + let k = mul k prime64_1 in 84 + h := logxor !h k; 85 + h := rotl64 !h 27; 86 + h := add (mul !h prime64_1) prime64_4; 87 + p := !p + 8 88 + done; 89 + 90 + (* Process remaining 4-byte chunk *) 91 + if !p + 4 <= end_pos then begin 92 + let k = of_int (Bytes.get_int32_le src !p |> Int32.to_int) in 93 + let k = logand k 0xFFFFFFFFL in (* Make unsigned *) 94 + h := logxor !h (mul k prime64_1); 95 + h := rotl64 !h 23; 96 + h := add (mul !h prime64_2) prime64_3; 97 + p := !p + 4 98 + end; 99 + 100 + (* Process remaining bytes *) 101 + while !p < end_pos do 102 + let k = of_int (Bytes.get_uint8 src !p) in 103 + h := logxor !h (mul k prime64_5); 104 + h := rotl64 !h 11; 105 + h := mul !h prime64_1; 106 + incr p 107 + done; 108 + 109 + avalanche !h 110 + 111 + let hash64_string ?seed s = 112 + let src = Bytes.unsafe_of_string s in 113 + hash64 ?seed src ~pos:0 ~len:(String.length s) 114 + 115 + (** Compute xxHash-64 and return lower 32 bits (for zstd checksum) *) 116 + let hash32 ?seed src ~pos ~len = 117 + let h = hash64 ?seed src ~pos ~len in 118 + Int64.to_int32 (Int64.logand h 0xFFFFFFFFL) 119 + 120 + let hash32_string ?seed s = 121 + let src = Bytes.unsafe_of_string s in 122 + hash32 ?seed src ~pos:0 ~len:(String.length s) 123 + 124 + (** Streaming hasher state *) 125 + type state = { 126 + mutable v1 : int64; 127 + mutable v2 : int64; 128 + mutable v3 : int64; 129 + mutable v4 : int64; 130 + mutable total_len : int; 131 + buffer : bytes; 132 + mutable buf_len : int; 133 + seed : int64; 134 + } 135 + 136 + let create_state ?(seed=0L) () = 137 + let open Int64 in 138 + { 139 + v1 = add (add seed prime64_1) prime64_2; 140 + v2 = add seed prime64_2; 141 + v3 = seed; 142 + v4 = sub seed prime64_1; 143 + total_len = 0; 144 + buffer = Bytes.create 32; 145 + buf_len = 0; 146 + seed; 147 + } 148 + 149 + let reset ?(seed=0L) state = 150 + let open Int64 in 151 + state.v1 <- add (add seed prime64_1) prime64_2; 152 + state.v2 <- add seed prime64_2; 153 + state.v3 <- seed; 154 + state.v4 <- sub seed prime64_1; 155 + state.total_len <- 0; 156 + state.buf_len <- 0 157 + 158 + let copy_state state = 159 + { 160 + v1 = state.v1; 161 + v2 = state.v2; 162 + v3 = state.v3; 163 + v4 = state.v4; 164 + total_len = state.total_len; 165 + buffer = Bytes.copy state.buffer; 166 + buf_len = state.buf_len; 167 + seed = state.seed; 168 + } 169 + 170 + let update state src ~pos ~len = 171 + let end_pos = pos + len in 172 + state.total_len <- state.total_len + len; 173 + 174 + let p = ref pos in 175 + 176 + (* Fill buffer if we have partial data *) 177 + if state.buf_len > 0 then begin 178 + let to_copy = min (32 - state.buf_len) len in 179 + Bytes.blit src !p state.buffer state.buf_len to_copy; 180 + state.buf_len <- state.buf_len + to_copy; 181 + p := !p + to_copy; 182 + 183 + if state.buf_len = 32 then begin 184 + state.v1 <- mix1 state.v1 (Bytes.get_int64_le state.buffer 0); 185 + state.v2 <- mix1 state.v2 (Bytes.get_int64_le state.buffer 8); 186 + state.v3 <- mix1 state.v3 (Bytes.get_int64_le state.buffer 16); 187 + state.v4 <- mix1 state.v4 (Bytes.get_int64_le state.buffer 24); 188 + state.buf_len <- 0 189 + end 190 + end; 191 + 192 + (* Process 32-byte blocks *) 193 + while !p + 32 <= end_pos do 194 + state.v1 <- mix1 state.v1 (Bytes.get_int64_le src !p); 195 + state.v2 <- mix1 state.v2 (Bytes.get_int64_le src (!p + 8)); 196 + state.v3 <- mix1 state.v3 (Bytes.get_int64_le src (!p + 16)); 197 + state.v4 <- mix1 state.v4 (Bytes.get_int64_le src (!p + 24)); 198 + p := !p + 32 199 + done; 200 + 201 + (* Buffer remaining *) 202 + if !p < end_pos then begin 203 + let remaining = end_pos - !p in 204 + Bytes.blit src !p state.buffer state.buf_len remaining; 205 + state.buf_len <- state.buf_len + remaining 206 + end 207 + 208 + let update_string state s = 209 + let src = Bytes.unsafe_of_string s in 210 + update state src ~pos:0 ~len:(String.length s) 211 + 212 + let finalize state = 213 + let open Int64 in 214 + 215 + let h = ref ( 216 + if state.total_len >= 32 then begin 217 + let h = add 218 + (add (rotl64 state.v1 1) (rotl64 state.v2 7)) 219 + (add (rotl64 state.v3 12) (rotl64 state.v4 18)) in 220 + let h = mix2 h state.v1 in 221 + let h = mix2 h state.v2 in 222 + let h = mix2 h state.v3 in 223 + mix2 h state.v4 224 + end else 225 + add state.v3 prime64_5 (* v3 holds seed *) 226 + ) in 227 + 228 + h := add !h (of_int state.total_len); 229 + 230 + (* Process buffered data *) 231 + let p = ref 0 in 232 + while !p + 8 <= state.buf_len do 233 + let k = Bytes.get_int64_le state.buffer !p in 234 + let k = mul k prime64_2 in 235 + let k = rotl64 k 31 in 236 + let k = mul k prime64_1 in 237 + h := logxor !h k; 238 + h := rotl64 !h 27; 239 + h := add (mul !h prime64_1) prime64_4; 240 + p := !p + 8 241 + done; 242 + 243 + if !p + 4 <= state.buf_len then begin 244 + let k = of_int (Bytes.get_int32_le state.buffer !p |> Int32.to_int) in 245 + let k = logand k 0xFFFFFFFFL in 246 + h := logxor !h (mul k prime64_1); 247 + h := rotl64 !h 23; 248 + h := add (mul !h prime64_2) prime64_3; 249 + p := !p + 4 250 + end; 251 + 252 + while !p < state.buf_len do 253 + let k = of_int (Bytes.get_uint8 state.buffer !p) in 254 + h := logxor !h (mul k prime64_5); 255 + h := rotl64 !h 11; 256 + h := mul !h prime64_1; 257 + incr p 258 + done; 259 + 260 + avalanche !h 261 + 262 + let finalize32 state = 263 + let h = finalize state in 264 + Int64.to_int32 (Int64.logand h 0xFFFFFFFFL)
+91
vendor/opam/ocaml-xxhash/src/xxhash.mli
··· 1 + (** xxHash - Fast non-cryptographic hash functions. 2 + 3 + This is a pure OCaml implementation of the xxHash family of hash functions, 4 + originally designed by Yann Collet. xxHash provides extremely fast hashing 5 + with excellent distribution properties. 6 + 7 + {1 Quick Start} 8 + 9 + {[ 10 + (* Hash a string *) 11 + let hash = Xxhash.hash64_string "Hello, World!" 12 + 13 + (* Hash bytes with explicit range *) 14 + let bytes = Bytes.of_string "Hello, World!" 15 + let hash = Xxhash.hash64 bytes ~pos:0 ~len:13 16 + 17 + (* Use streaming API for large data *) 18 + let state = Xxhash.create_state () in 19 + Xxhash.update state chunk1 ~pos:0 ~len:(Bytes.length chunk1); 20 + Xxhash.update state chunk2 ~pos:0 ~len:(Bytes.length chunk2); 21 + let hash = Xxhash.finalize state 22 + ]} 23 + 24 + {1 Hash Variants} 25 + 26 + - {!hash64}: 64-bit hash, best for general use 27 + - {!hash32}: Lower 32 bits of 64-bit hash (used by zstd) 28 + 29 + {1 Streaming API} 30 + 31 + For hashing data that doesn't fit in memory or arrives incrementally: 32 + - {!create_state}: Create a new streaming state 33 + - {!update}: Feed data into the state 34 + - {!finalize}: Get the final hash value *) 35 + 36 + (** {1 One-shot Hashing} *) 37 + 38 + val hash64 : ?seed:int64 -> bytes -> pos:int -> len:int -> int64 39 + (** [hash64 ?seed bytes ~pos ~len] computes the xxHash-64 of [len] bytes 40 + from [bytes] starting at [pos]. 41 + 42 + @param seed Optional seed value (default: 0) *) 43 + 44 + val hash64_string : ?seed:int64 -> string -> int64 45 + (** [hash64_string ?seed s] computes the xxHash-64 of string [s]. *) 46 + 47 + val hash32 : ?seed:int64 -> bytes -> pos:int -> len:int -> int32 48 + (** [hash32 ?seed bytes ~pos ~len] computes xxHash-64 and returns the 49 + lower 32 bits. This is the variant used by zstd for content checksums. *) 50 + 51 + val hash32_string : ?seed:int64 -> string -> int32 52 + (** [hash32_string ?seed s] computes the lower 32 bits of xxHash-64. *) 53 + 54 + (** {1 Streaming API} *) 55 + 56 + (** Streaming hasher state. *) 57 + type state 58 + 59 + val create_state : ?seed:int64 -> unit -> state 60 + (** [create_state ?seed ()] creates a new streaming hash state. 61 + 62 + @param seed Optional seed value (default: 0) *) 63 + 64 + val reset : ?seed:int64 -> state -> unit 65 + (** [reset ?seed state] resets the state for reuse with a new hash. 66 + 67 + @param seed Optional new seed value (default: 0) *) 68 + 69 + val update : state -> bytes -> pos:int -> len:int -> unit 70 + (** [update state bytes ~pos ~len] feeds [len] bytes from [bytes] 71 + starting at [pos] into the hash state. 72 + 73 + Can be called multiple times to hash data incrementally. *) 74 + 75 + val update_string : state -> string -> unit 76 + (** [update_string state s] feeds string [s] into the hash state. *) 77 + 78 + val finalize : state -> int64 79 + (** [finalize state] returns the 64-bit hash value. 80 + 81 + The state can still be used after finalization - subsequent calls 82 + to {!finalize} return the same value until {!update} is called. *) 83 + 84 + val finalize32 : state -> int32 85 + (** [finalize32 state] returns the lower 32 bits of the hash. *) 86 + 87 + (** {1 Utilities} *) 88 + 89 + val copy_state : state -> state 90 + (** [copy_state state] creates an independent copy of the hash state. 91 + Useful for computing hashes of data with common prefixes. *)
+3
vendor/opam/ocaml-xxhash/test/dune
··· 1 + (test 2 + (name test_xxhash) 3 + (libraries xxhash alcotest))
+232
vendor/opam/ocaml-xxhash/test/test_xxhash.ml
··· 1 + (** Tests for xxHash-64 implementation. 2 + 3 + This test suite verifies: 4 + 1. Internal consistency (streaming vs one-shot produce same results) 5 + 2. Known reference values for empty string 6 + 3. Boundary conditions (32-byte blocks, various lengths) 7 + 8 + TODO: Add tests against reference C implementation (see STATUS.md) *) 9 + 10 + (* Known reference value: xxhash64("") with seed 0 *) 11 + let test_empty_string () = 12 + let hash = Xxhash.hash64_string "" in 13 + Alcotest.(check int64) "empty string" 0xef46db3751d8e999L hash 14 + 15 + (* Consistency tests - verify streaming and one-shot produce same results *) 16 + let test_consistency_short () = 17 + let s = "Hello" in 18 + let direct = Xxhash.hash64_string s in 19 + let state = Xxhash.create_state () in 20 + Xxhash.update_string state s; 21 + let streaming = Xxhash.finalize state in 22 + Alcotest.(check int64) "short string consistency" direct streaming 23 + 24 + let test_consistency_medium () = 25 + let s = "Hello, World!" in 26 + let direct = Xxhash.hash64_string s in 27 + let state = Xxhash.create_state () in 28 + Xxhash.update_string state s; 29 + let streaming = Xxhash.finalize state in 30 + Alcotest.(check int64) "medium string consistency" direct streaming 31 + 32 + let test_consistency_with_seed () = 33 + let s = "test data" in 34 + let seed = 12345L in 35 + let direct = Xxhash.hash64_string ~seed s in 36 + let state = Xxhash.create_state ~seed () in 37 + Xxhash.update_string state s; 38 + let streaming = Xxhash.finalize state in 39 + Alcotest.(check int64) "consistency with seed" direct streaming 40 + 41 + (* Boundary condition: exactly 32 bytes (one block) *) 42 + let test_32_bytes () = 43 + let s = String.make 32 'x' in 44 + let direct = Xxhash.hash64_string s in 45 + let state = Xxhash.create_state () in 46 + Xxhash.update_string state s; 47 + let streaming = Xxhash.finalize state in 48 + Alcotest.(check int64) "32 bytes consistency" direct streaming 49 + 50 + (* Boundary condition: 33 bytes (one block + 1 byte) *) 51 + let test_33_bytes () = 52 + let s = String.make 33 'y' in 53 + let direct = Xxhash.hash64_string s in 54 + let state = Xxhash.create_state () in 55 + Xxhash.update_string state s; 56 + let streaming = Xxhash.finalize state in 57 + Alcotest.(check int64) "33 bytes consistency" direct streaming 58 + 59 + (* Boundary condition: 64 bytes (two blocks) *) 60 + let test_64_bytes () = 61 + let s = String.make 64 'a' in 62 + let direct = Xxhash.hash64_string s in 63 + let state = Xxhash.create_state () in 64 + Xxhash.update_string state s; 65 + let streaming = Xxhash.finalize state in 66 + Alcotest.(check int64) "64 bytes consistency" direct streaming 67 + 68 + (* hash32 consistency *) 69 + let test_hash32_consistency () = 70 + let s = "Hello, World!" in 71 + let hash64 = Xxhash.hash64_string s in 72 + let hash32 = Xxhash.hash32_string s in 73 + let expected32 = Int64.to_int32 (Int64.logand hash64 0xFFFFFFFFL) in 74 + Alcotest.(check int32) "hash32 is lower 32 bits" expected32 hash32 75 + 76 + let test_streaming_chunks () = 77 + (* Hash in multiple chunks, should match single hash *) 78 + let state = Xxhash.create_state () in 79 + Xxhash.update_string state "Hello"; 80 + Xxhash.update_string state ", "; 81 + Xxhash.update_string state "World!"; 82 + let hash = Xxhash.finalize state in 83 + let direct = Xxhash.hash64_string "Hello, World!" in 84 + Alcotest.(check int64) "chunked streaming" direct hash 85 + 86 + let test_streaming_byte_at_a_time () = 87 + let s = "Hello, World!" in 88 + let state = Xxhash.create_state () in 89 + String.iter (fun c -> 90 + Xxhash.update_string state (String.make 1 c) 91 + ) s; 92 + let hash = Xxhash.finalize state in 93 + let direct = Xxhash.hash64_string s in 94 + Alcotest.(check int64) "byte-at-a-time" direct hash 95 + 96 + let test_streaming_large () = 97 + (* Large data in chunks *) 98 + let chunk = String.make 100 'z' in 99 + let state = Xxhash.create_state () in 100 + for _ = 1 to 10 do 101 + Xxhash.update_string state chunk 102 + done; 103 + let hash = Xxhash.finalize state in 104 + let direct = Xxhash.hash64_string (String.make 1000 'z') in 105 + Alcotest.(check int64) "large streaming" direct hash 106 + 107 + let test_streaming_across_boundary () = 108 + (* Feed data that crosses 32-byte block boundaries *) 109 + let state = Xxhash.create_state () in 110 + Xxhash.update_string state (String.make 20 'a'); 111 + Xxhash.update_string state (String.make 20 'b'); 112 + Xxhash.update_string state (String.make 20 'c'); 113 + let hash = Xxhash.finalize state in 114 + let direct = Xxhash.hash64_string (String.make 20 'a' ^ String.make 20 'b' ^ String.make 20 'c') in 115 + Alcotest.(check int64) "across boundary" direct hash 116 + 117 + let test_reset () = 118 + let state = Xxhash.create_state () in 119 + Xxhash.update_string state "first data"; 120 + let _ = Xxhash.finalize state in 121 + Xxhash.reset state; 122 + Xxhash.update_string state "second data"; 123 + let hash = Xxhash.finalize state in 124 + let direct = Xxhash.hash64_string "second data" in 125 + Alcotest.(check int64) "after reset" direct hash 126 + 127 + let test_reset_with_new_seed () = 128 + let state = Xxhash.create_state ~seed:111L () in 129 + Xxhash.update_string state "first"; 130 + let _ = Xxhash.finalize state in 131 + Xxhash.reset ~seed:222L state; 132 + Xxhash.update_string state "second"; 133 + let hash = Xxhash.finalize state in 134 + let direct = Xxhash.hash64_string ~seed:222L "second" in 135 + Alcotest.(check int64) "reset with new seed" direct hash 136 + 137 + let test_copy_state () = 138 + let state1 = Xxhash.create_state () in 139 + Xxhash.update_string state1 "Hello"; 140 + let state2 = Xxhash.copy_state state1 in 141 + Xxhash.update_string state1 ", World!"; 142 + Xxhash.update_string state2 " there"; 143 + let hash1 = Xxhash.finalize state1 in 144 + let hash2 = Xxhash.finalize state2 in 145 + let direct1 = Xxhash.hash64_string "Hello, World!" in 146 + let direct2 = Xxhash.hash64_string "Hello there" in 147 + Alcotest.(check int64) "original state" direct1 hash1; 148 + Alcotest.(check int64) "copied state" direct2 hash2 149 + 150 + let test_finalize32 () = 151 + let state = Xxhash.create_state () in 152 + Xxhash.update_string state "test"; 153 + let hash32 = Xxhash.finalize32 state in 154 + let hash64 = Xxhash.finalize state in 155 + let expected32 = Int64.to_int32 (Int64.logand hash64 0xFFFFFFFFL) in 156 + Alcotest.(check int32) "finalize32" expected32 hash32 157 + 158 + let test_bytes_api () = 159 + let s = "Hello, World!" in 160 + let bytes = Bytes.of_string s in 161 + let from_string = Xxhash.hash64_string s in 162 + let from_bytes = Xxhash.hash64 bytes ~pos:0 ~len:(Bytes.length bytes) in 163 + Alcotest.(check int64) "bytes API consistency" from_string from_bytes 164 + 165 + let test_bytes_partial () = 166 + let bytes = Bytes.of_string "XXXHello, World!YYY" in 167 + let hash = Xxhash.hash64 bytes ~pos:3 ~len:13 in 168 + let direct = Xxhash.hash64_string "Hello, World!" in 169 + Alcotest.(check int64) "partial bytes" direct hash 170 + 171 + (* Determinism test *) 172 + let test_deterministic () = 173 + let s = "The quick brown fox jumps over the lazy dog" in 174 + let hash1 = Xxhash.hash64_string s in 175 + let hash2 = Xxhash.hash64_string s in 176 + let hash3 = Xxhash.hash64_string s in 177 + Alcotest.(check int64) "hash1 = hash2" hash1 hash2; 178 + Alcotest.(check int64) "hash2 = hash3" hash2 hash3 179 + 180 + (* Different inputs produce different hashes *) 181 + let test_different_inputs () = 182 + let h1 = Xxhash.hash64_string "hello" in 183 + let h2 = Xxhash.hash64_string "Hello" in 184 + let h3 = Xxhash.hash64_string "hello " in 185 + Alcotest.(check bool) "hello != Hello" true (h1 <> h2); 186 + Alcotest.(check bool) "hello != 'hello '" true (h1 <> h3) 187 + 188 + (* Different seeds produce different hashes *) 189 + let test_different_seeds () = 190 + let s = "test" in 191 + let h1 = Xxhash.hash64_string ~seed:0L s in 192 + let h2 = Xxhash.hash64_string ~seed:1L s in 193 + let h3 = Xxhash.hash64_string ~seed:42L s in 194 + Alcotest.(check bool) "seed 0 != seed 1" true (h1 <> h2); 195 + Alcotest.(check bool) "seed 1 != seed 42" true (h2 <> h3) 196 + 197 + let () = 198 + Alcotest.run "xxhash" [ 199 + "reference", [ 200 + Alcotest.test_case "empty string" `Quick test_empty_string; 201 + ]; 202 + "consistency", [ 203 + Alcotest.test_case "short" `Quick test_consistency_short; 204 + Alcotest.test_case "medium" `Quick test_consistency_medium; 205 + Alcotest.test_case "with seed" `Quick test_consistency_with_seed; 206 + Alcotest.test_case "hash32" `Quick test_hash32_consistency; 207 + Alcotest.test_case "bytes API" `Quick test_bytes_api; 208 + Alcotest.test_case "partial bytes" `Quick test_bytes_partial; 209 + ]; 210 + "boundaries", [ 211 + Alcotest.test_case "32 bytes" `Quick test_32_bytes; 212 + Alcotest.test_case "33 bytes" `Quick test_33_bytes; 213 + Alcotest.test_case "64 bytes" `Quick test_64_bytes; 214 + ]; 215 + "streaming", [ 216 + Alcotest.test_case "chunks" `Quick test_streaming_chunks; 217 + Alcotest.test_case "byte at a time" `Quick test_streaming_byte_at_a_time; 218 + Alcotest.test_case "large" `Quick test_streaming_large; 219 + Alcotest.test_case "across boundary" `Quick test_streaming_across_boundary; 220 + ]; 221 + "state", [ 222 + Alcotest.test_case "reset" `Quick test_reset; 223 + Alcotest.test_case "reset with seed" `Quick test_reset_with_new_seed; 224 + Alcotest.test_case "copy" `Quick test_copy_state; 225 + Alcotest.test_case "finalize32" `Quick test_finalize32; 226 + ]; 227 + "properties", [ 228 + Alcotest.test_case "deterministic" `Quick test_deterministic; 229 + Alcotest.test_case "different inputs" `Quick test_different_inputs; 230 + Alcotest.test_case "different seeds" `Quick test_different_seeds; 231 + ]; 232 + ]
+22
vendor/opam/ocaml-xxhash/xxhash.opam
··· 1 + opam-version: "2.0" 2 + name: "xxhash" 3 + version: "0.1.0" 4 + synopsis: "Pure OCaml implementation of xxHash-64" 5 + description: """ 6 + A pure OCaml implementation of the xxHash-64 non-cryptographic hash algorithm. 7 + Provides both one-shot and streaming APIs for hashing bytes and strings. 8 + """ 9 + maintainer: ["Your Name <you@example.com>"] 10 + authors: ["Your Name <you@example.com>"] 11 + license: "MIT" 12 + homepage: "https://github.com/yourname/ocaml-xxhash" 13 + bug-reports: "https://github.com/yourname/ocaml-xxhash/issues" 14 + depends: [ 15 + "ocaml" {>= "4.14.0"} 16 + "dune" {>= "3.0"} 17 + "alcotest" {with-test} 18 + ] 19 + build: [ 20 + ["dune" "build" "-p" name "-j" jobs] 21 + ["dune" "runtest" "-p" name "-j" jobs] {with-test} 22 + ]