File Coverage

xxh64.c
Criterion Covered Total %
statement 91 100 91.0
branch 15 20 75.0
condition n/a
subroutine n/a
pod n/a
total 106 120 88.3


line stmt bran cond sub pod time code
1             /*
2             * xxh64.c - XXH64 implementation per the xxHash specification.
3             *
4             * Big-endian/little-endian agnostic via byte-by-byte loaders. The
5             * algorithm itself is little-endian for input lanes; we read each
6             * lane bytewise, never type-pun.
7             */
8              
9             #include "xxh64.h"
10             #include
11              
12             #define ROL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
13              
14             #define PRIME64_1 0x9E3779B185EBCA87ULL
15             #define PRIME64_2 0xC2B2AE3D27D4EB4FULL
16             #define PRIME64_3 0x165667B19E3779F9ULL
17             #define PRIME64_4 0x85EBCA77C2B2AE63ULL
18             #define PRIME64_5 0x27D4EB2F165667C5ULL
19              
20             static uint64_t
21 17508           load64_le(const unsigned char *p)
22             {
23 17508           return (uint64_t)p[0]
24 17508           | ((uint64_t)p[1] << 8)
25 17508           | ((uint64_t)p[2] << 16)
26 17508           | ((uint64_t)p[3] << 24)
27 17508           | ((uint64_t)p[4] << 32)
28 17508           | ((uint64_t)p[5] << 40)
29 17508           | ((uint64_t)p[6] << 48)
30 17508           | ((uint64_t)p[7] << 56);
31             }
32              
33             static uint32_t
34 2           load32_le(const unsigned char *p)
35             {
36 2           return (uint32_t)p[0]
37 2           | ((uint32_t)p[1] << 8)
38 2           | ((uint32_t)p[2] << 16)
39 2           | ((uint32_t)p[3] << 24);
40             }
41              
42             static uint64_t
43 17524           xxh64_round(uint64_t acc, uint64_t input)
44             {
45 17524           acc += input * PRIME64_2;
46 17524           acc = ROL64(acc, 31);
47 17524           acc *= PRIME64_1;
48 17524           return acc;
49             }
50              
51             static uint64_t
52 16           xxh64_merge_round(uint64_t acc, uint64_t val)
53             {
54 16           val = xxh64_round(0, val);
55 16           acc ^= val;
56 16           acc = acc * PRIME64_1 + PRIME64_4;
57 16           return acc;
58             }
59              
60             void
61 10           xxh64_init(xxh64_ctx_t *ctx, uint64_t seed)
62             {
63 10           ctx->v[0] = seed + PRIME64_1 + PRIME64_2;
64 10           ctx->v[1] = seed + PRIME64_2;
65 10           ctx->v[2] = seed + 0;
66 10           ctx->v[3] = seed - PRIME64_1;
67 10           ctx->total_len = 0;
68 10           ctx->seed = seed;
69 10           ctx->large_path_seen = 0;
70 10           ctx->buffered = 0;
71 10           }
72              
73             static void
74 4376           xxh64_consume_stripe(xxh64_ctx_t *ctx, const unsigned char *p)
75             {
76 4376           ctx->v[0] = xxh64_round(ctx->v[0], load64_le(p ));
77 4376           ctx->v[1] = xxh64_round(ctx->v[1], load64_le(p + 8));
78 4376           ctx->v[2] = xxh64_round(ctx->v[2], load64_le(p + 16));
79 4376           ctx->v[3] = xxh64_round(ctx->v[3], load64_le(p + 24));
80 4376           ctx->large_path_seen = 1;
81 4376           }
82              
83             void
84 8           xxh64_update(xxh64_ctx_t *ctx, const void *data, size_t len)
85             {
86 8           const unsigned char *p = (const unsigned char *)data;
87             size_t take;
88              
89 8           ctx->total_len += len;
90              
91             /* Drain the partial-stripe buffer if it can complete a stripe. */
92 8 50         if (ctx->buffered) {
93 0           take = XXH64_BLOCK_SIZE - ctx->buffered;
94 0 0         if (take > len) take = len;
95 0           memcpy(ctx->buffer + ctx->buffered, p, take);
96 0           ctx->buffered += take;
97 0           p += take;
98 0           len -= take;
99 0 0         if (ctx->buffered == XXH64_BLOCK_SIZE) {
100 0           xxh64_consume_stripe(ctx, ctx->buffer);
101 0           ctx->buffered = 0;
102             }
103             }
104              
105 4384 100         while (len >= XXH64_BLOCK_SIZE) {
106 4376           xxh64_consume_stripe(ctx, p);
107 4376           p += XXH64_BLOCK_SIZE;
108 4376           len -= XXH64_BLOCK_SIZE;
109             }
110              
111 8 100         if (len) {
112 7           memcpy(ctx->buffer, p, len);
113 7           ctx->buffered = len;
114             }
115 8           }
116              
117             void
118 10           xxh64_final(xxh64_ctx_t *ctx, unsigned char out[XXH64_DIGEST_SIZE])
119             {
120             uint64_t h;
121 10           const unsigned char *p = ctx->buffer;
122 10           size_t remaining = ctx->buffered;
123             int i;
124              
125 10 100         if (ctx->large_path_seen) {
126 4           h = ROL64(ctx->v[0], 1) + ROL64(ctx->v[1], 7)
127 4           + ROL64(ctx->v[2], 12) + ROL64(ctx->v[3], 18);
128 4           h = xxh64_merge_round(h, ctx->v[0]);
129 4           h = xxh64_merge_round(h, ctx->v[1]);
130 4           h = xxh64_merge_round(h, ctx->v[2]);
131 4           h = xxh64_merge_round(h, ctx->v[3]);
132             } else {
133 6           h = ctx->seed + PRIME64_5;
134             }
135              
136 10           h += ctx->total_len;
137              
138             /* Process remaining bytes: 8-byte, then 4-byte, then 1-byte
139             * chunks per the spec's mix table. */
140 14 100         while (remaining >= 8) {
141 4           uint64_t k = load64_le(p);
142 4           k = xxh64_round(0, k);
143 4           h ^= k;
144 4           h = ROL64(h, 27) * PRIME64_1 + PRIME64_4;
145 4           p += 8;
146 4           remaining -= 8;
147             }
148 10 100         if (remaining >= 4) {
149 2           uint64_t k = (uint64_t)load32_le(p);
150 2           h ^= k * PRIME64_1;
151 2           h = ROL64(h, 23) * PRIME64_2 + PRIME64_3;
152 2           p += 4;
153 2           remaining -= 4;
154             }
155 27 100         while (remaining > 0) {
156 17           h ^= (uint64_t)(*p) * PRIME64_5;
157 17           h = ROL64(h, 11) * PRIME64_1;
158 17           p++;
159 17           remaining--;
160             }
161              
162             /* Avalanche. */
163 10           h ^= h >> 33;
164 10           h *= PRIME64_2;
165 10           h ^= h >> 29;
166 10           h *= PRIME64_3;
167 10           h ^= h >> 32;
168              
169             /* Big-endian output: matches conventional hex display
170             * (xxhsum -H64). */
171 90 100         for (i = 0; i < 8; i++) {
172 80           out[i] = (unsigned char)((h >> (56 - i * 8)) & 0xFFu);
173             }
174 10           }