GCC Code Coverage Report


Directory: ./
File: hash_key.c
Date: 2025-11-30 14:18:36
Exec Total Coverage
Lines: 88 88 100.0%
Functions: 12 12 100.0%
Branches: 18 18 100.0%

Line Branch Exec Source
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "cx/hash_key.h"
30 #include "cx/compare.h"
31 #include <string.h>
32
33 628 void cx_hash_murmur(CxHashKey *key) {
34 628 const unsigned char *data = key->data;
35
2/2
✓ Branch 0 (2→3) taken 4 times.
✓ Branch 1 (2→4) taken 624 times.
628 if (data == NULL) {
36 // extension: special value for NULL
37 4 key->hash = 1574210520u;
38 4 return;
39 }
40 624 size_t len = key->len;
41
42 624 unsigned m = 0x5bd1e995;
43 624 unsigned r = 24;
44 624 unsigned h = 25 ^ (unsigned) len;
45 624 unsigned i = 0;
46
2/2
✓ Branch 0 (6→5) taken 444 times.
✓ Branch 1 (6→7) taken 624 times.
1068 while (len >= 4) {
47 444 unsigned k = data[i + 0] & 0xFF;
48 444 k |= (data[i + 1] & 0xFF) << 8;
49 444 k |= (data[i + 2] & 0xFF) << 16;
50 444 k |= (data[i + 3] & 0xFF) << 24;
51
52 444 k *= m;
53 444 k ^= k >> r;
54 444 k *= m;
55
56 444 h *= m;
57 444 h ^= k;
58
59 444 i += 4;
60 444 len -= 4;
61 }
62
63
4/4
✓ Branch 0 (7→8) taken 158 times.
✓ Branch 1 (7→9) taken 296 times.
✓ Branch 2 (7→10) taken 129 times.
✓ Branch 3 (7→11) taken 41 times.
624 switch (len) {
64 158 case 3:
65 158 h ^= (data[i + 2] & 0xFF) << 16;
66 cx_attr_fallthrough;
67 454 case 2:
68 454 h ^= (data[i + 1] & 0xFF) << 8;
69 cx_attr_fallthrough;
70 583 case 1:
71 583 h ^= (data[i + 0] & 0xFF);
72 583 h *= m;
73 cx_attr_fallthrough;
74 624 default: // do nothing
75 ;
76 }
77
78 624 h ^= h >> 13;
79 624 h *= m;
80 624 h ^= h >> 15;
81
82 624 key->hash = h;
83 }
84
85
86 4 uint32_t cx_hash_u32(uint32_t x) {
87 4 x = ((x >> 16) ^ x) * 0x45d9f3bu;
88 4 x = ((x >> 16) ^ x) * 0x45d9f3bu;
89 4 x = (x >> 16) ^ x;
90 4 return x;
91 }
92
93 4 uint64_t cx_hash_u64(uint64_t x) {
94 4 x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
95 4 x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
96 4 x = x ^ (x >> 31);
97 4 return x;
98 }
99
100 563 CxHashKey cx_hash_key_str(const char *str) {
101 CxHashKey key;
102 563 key.data = str;
103
2/2
✓ Branch 0 (2→3) taken 562 times.
✓ Branch 1 (2→4) taken 1 times.
563 key.len = str == NULL ? 0 : strlen(str);
104 563 cx_hash_murmur(&key);
105 563 return key;
106 }
107
108 4 CxHashKey cx_hash_key_ustr(unsigned const char *str) {
109 CxHashKey key;
110 4 key.data = str;
111
2/2
✓ Branch 0 (2→3) taken 3 times.
✓ Branch 1 (2→4) taken 1 times.
4 key.len = str == NULL ? 0 : strlen((const char*)str);
112 4 cx_hash_murmur(&key);
113 4 return key;
114 }
115
116 20 CxHashKey cx_hash_key_cxstr(cxstring str) {
117 20 return cx_hash_key(str.ptr, str.length);
118 }
119
120 2 CxHashKey cx_hash_key_mutstr(cxmutstr str) {
121 2 return cx_hash_key(str.ptr, str.length);
122 }
123
124 3 CxHashKey cx_hash_key_bytes(
125 const unsigned char *bytes,
126 size_t len
127 ) {
128 CxHashKey key;
129 3 key.data = bytes;
130 3 key.len = len;
131 3 cx_hash_murmur(&key);
132 3 return key;
133 }
134
135 26 CxHashKey cx_hash_key(
136 const void *obj,
137 size_t len
138 ) {
139 CxHashKey key;
140 26 key.data = obj;
141 26 key.len = len;
142 26 cx_hash_murmur(&key);
143 26 return key;
144 }
145
146 4 CxHashKey cx_hash_key_u32(uint32_t x) {
147 CxHashKey key;
148 4 key.data = NULL;
149 4 key.len = 0;
150 4 key.hash = cx_hash_u32(x);
151 4 return key;
152 }
153
154 4 CxHashKey cx_hash_key_u64(uint64_t x) {
155 CxHashKey key;
156 4 key.data = NULL;
157 4 key.len = 0;
158 4 key.hash = cx_hash_u64(x);
159 4 return key;
160 }
161
162 376 int cx_hash_key_cmp(const void *l, const void *r) {
163 376 const CxHashKey *left = l;
164 376 const CxHashKey *right = r;
165 int d;
166 376 d = cx_vcmp_uint64(left->hash, right->hash);
167
2/2
✓ Branch 0 (3→4) taken 84 times.
✓ Branch 1 (3→5) taken 292 times.
376 if (d != 0) return d;
168 292 d = cx_vcmp_size(left->len, right->len);
169
2/2
✓ Branch 0 (6→7) taken 1 times.
✓ Branch 1 (6→8) taken 291 times.
292 if (d != 0) return d;
170
2/2
✓ Branch 0 (8→9) taken 2 times.
✓ Branch 1 (8→10) taken 289 times.
291 if (left->len == 0) return 0;
171 289 return memcmp(left->data, right->data, left->len);
172 }
173