/src/PROJ/curl/lib/uint-bset.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*************************************************************************** |
2 | | * _ _ ____ _ |
3 | | * Project ___| | | | _ \| | |
4 | | * / __| | | | |_) | | |
5 | | * | (__| |_| | _ <| |___ |
6 | | * \___|\___/|_| \_\_____| |
7 | | * |
8 | | * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. |
9 | | * |
10 | | * This software is licensed as described in the file COPYING, which |
11 | | * you should have received as part of this distribution. The terms |
12 | | * are also available at https://curl.se/docs/copyright.html. |
13 | | * |
14 | | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
15 | | * copies of the Software, and permit persons to whom the Software is |
16 | | * furnished to do so, under the terms of the COPYING file. |
17 | | * |
18 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
19 | | * KIND, either express or implied. |
20 | | * |
21 | | * SPDX-License-Identifier: curl |
22 | | * |
23 | | ***************************************************************************/ |
24 | | |
25 | | #include "curl_setup.h" |
26 | | #include "uint-bset.h" |
27 | | |
28 | | /* The last 3 #include files should be in this order */ |
29 | | #include "curl_printf.h" |
30 | | #include "curl_memory.h" |
31 | | #include "memdebug.h" |
32 | | |
33 | | #ifdef DEBUGBUILD |
34 | | #define CURL_UINT_BSET_MAGIC 0x62757473 |
35 | | #endif |
36 | | |
37 | | void Curl_uint_bset_init(struct uint_bset *bset) |
38 | 0 | { |
39 | 0 | memset(bset, 0, sizeof(*bset)); |
40 | | #ifdef DEBUGBUILD |
41 | | bset->init = CURL_UINT_BSET_MAGIC; |
42 | | #endif |
43 | 0 | } |
44 | | |
45 | | |
46 | | CURLcode Curl_uint_bset_resize(struct uint_bset *bset, unsigned int nmax) |
47 | 0 | { |
48 | 0 | unsigned int nslots = (nmax < (UINT_MAX-63)) ? |
49 | 0 | ((nmax + 63) / 64) : (UINT_MAX / 64); |
50 | |
|
51 | 0 | DEBUGASSERT(bset->init == CURL_UINT_BSET_MAGIC); |
52 | 0 | if(nslots != bset->nslots) { |
53 | 0 | curl_uint64_t *slots = calloc(nslots, sizeof(curl_uint64_t)); |
54 | 0 | if(!slots) |
55 | 0 | return CURLE_OUT_OF_MEMORY; |
56 | | |
57 | 0 | if(bset->slots) { |
58 | 0 | memcpy(slots, bset->slots, |
59 | 0 | (CURLMIN(nslots, bset->nslots) * sizeof(curl_uint64_t))); |
60 | 0 | free(bset->slots); |
61 | 0 | } |
62 | 0 | bset->slots = slots; |
63 | 0 | bset->nslots = nslots; |
64 | 0 | bset->first_slot_used = 0; |
65 | 0 | } |
66 | 0 | return CURLE_OK; |
67 | 0 | } |
68 | | |
69 | | |
70 | | void Curl_uint_bset_destroy(struct uint_bset *bset) |
71 | 0 | { |
72 | 0 | DEBUGASSERT(bset->init == CURL_UINT_BSET_MAGIC); |
73 | 0 | free(bset->slots); |
74 | 0 | memset(bset, 0, sizeof(*bset)); |
75 | 0 | } |
76 | | |
77 | | #ifdef UNITTESTS |
78 | | UNITTEST unsigned int Curl_uint_bset_capacity(struct uint_bset *bset) |
79 | | { |
80 | | return bset->nslots * 64; |
81 | | } |
82 | | |
83 | | UNITTEST unsigned int Curl_uint_bset_count(struct uint_bset *bset) |
84 | | { |
85 | | unsigned int i; |
86 | | unsigned int n = 0; |
87 | | for(i = 0; i < bset->nslots; ++i) { |
88 | | if(bset->slots[i]) |
89 | | n += CURL_POPCOUNT64(bset->slots[i]); |
90 | | } |
91 | | return n; |
92 | | } |
93 | | #endif |
94 | | |
95 | | bool Curl_uint_bset_empty(struct uint_bset *bset) |
96 | 0 | { |
97 | 0 | unsigned int i; |
98 | 0 | for(i = bset->first_slot_used; i < bset->nslots; ++i) { |
99 | 0 | if(bset->slots[i]) |
100 | 0 | return FALSE; |
101 | 0 | } |
102 | 0 | return TRUE; |
103 | 0 | } |
104 | | |
105 | | |
106 | | void Curl_uint_bset_clear(struct uint_bset *bset) |
107 | 0 | { |
108 | 0 | if(bset->nslots) { |
109 | 0 | memset(bset->slots, 0, bset->nslots * sizeof(curl_uint64_t)); |
110 | 0 | bset->first_slot_used = UINT_MAX; |
111 | 0 | } |
112 | 0 | } |
113 | | |
114 | | |
115 | | bool Curl_uint_bset_add(struct uint_bset *bset, unsigned int i) |
116 | 0 | { |
117 | 0 | unsigned int islot = i / 64; |
118 | 0 | if(islot >= bset->nslots) |
119 | 0 | return FALSE; |
120 | 0 | bset->slots[islot] |= ((curl_uint64_t)1 << (i % 64)); |
121 | 0 | if(islot < bset->first_slot_used) |
122 | 0 | bset->first_slot_used = islot; |
123 | 0 | return TRUE; |
124 | 0 | } |
125 | | |
126 | | |
127 | | void Curl_uint_bset_remove(struct uint_bset *bset, unsigned int i) |
128 | 0 | { |
129 | 0 | size_t islot = i / 64; |
130 | 0 | if(islot < bset->nslots) |
131 | 0 | bset->slots[islot] &= ~((curl_uint64_t)1 << (i % 64)); |
132 | 0 | } |
133 | | |
134 | | |
135 | | bool Curl_uint_bset_contains(struct uint_bset *bset, unsigned int i) |
136 | 0 | { |
137 | 0 | unsigned int islot = i / 64; |
138 | 0 | if(islot >= bset->nslots) |
139 | 0 | return FALSE; |
140 | 0 | return (bset->slots[islot] & ((curl_uint64_t)1 << (i % 64))) != 0; |
141 | 0 | } |
142 | | |
143 | | |
144 | | bool Curl_uint_bset_first(struct uint_bset *bset, unsigned int *pfirst) |
145 | 0 | { |
146 | 0 | unsigned int i; |
147 | 0 | for(i = bset->first_slot_used; i < bset->nslots; ++i) { |
148 | 0 | if(bset->slots[i]) { |
149 | 0 | *pfirst = (i * 64) + CURL_CTZ64(bset->slots[i]); |
150 | 0 | bset->first_slot_used = i; |
151 | 0 | return TRUE; |
152 | 0 | } |
153 | 0 | } |
154 | 0 | bset->first_slot_used = *pfirst = UINT_MAX; |
155 | 0 | return FALSE; |
156 | 0 | } |
157 | | |
158 | | bool Curl_uint_bset_next(struct uint_bset *bset, unsigned int last, |
159 | | unsigned int *pnext) |
160 | 0 | { |
161 | 0 | unsigned int islot; |
162 | 0 | curl_uint64_t x; |
163 | |
|
164 | 0 | ++last; /* look for number one higher than last */ |
165 | 0 | islot = last / 64; /* the slot this would be in */ |
166 | 0 | if(islot < bset->nslots) { |
167 | | /* shift away the bits we already iterated in this slot */ |
168 | 0 | x = (bset->slots[islot] >> (last % 64)); |
169 | 0 | if(x) { |
170 | | /* more bits set, next is `last` + trailing0s of the shifted slot */ |
171 | 0 | *pnext = last + CURL_CTZ64(x); |
172 | 0 | return TRUE; |
173 | 0 | } |
174 | | /* no more bits set in the last slot, scan forward */ |
175 | 0 | for(islot = islot + 1; islot < bset->nslots; ++islot) { |
176 | 0 | if(bset->slots[islot]) { |
177 | 0 | *pnext = (islot * 64) + CURL_CTZ64(bset->slots[islot]); |
178 | 0 | return TRUE; |
179 | 0 | } |
180 | 0 | } |
181 | 0 | } |
182 | 0 | *pnext = UINT_MAX; /* a value we cannot store */ |
183 | 0 | return FALSE; |
184 | 0 | } |
185 | | |
186 | | #ifdef CURL_POPCOUNT64_IMPLEMENT |
187 | | unsigned int Curl_popcount64(curl_uint64_t x) |
188 | | { |
189 | | /* Compute the "Hamming Distance" between 'x' and 0, |
190 | | * which is the number of set bits in 'x'. |
191 | | * See: https://en.wikipedia.org/wiki/Hamming_weight */ |
192 | | const curl_uint64_t m1 = 0x5555555555555555LL; /* 0101+ */ |
193 | | const curl_uint64_t m2 = 0x3333333333333333LL; /* 00110011+ */ |
194 | | const curl_uint64_t m4 = 0x0f0f0f0f0f0f0f0fLL; /* 00001111+ */ |
195 | | /* 1 + 256^1 + 256^2 + 256^3 + ... + 256^7 */ |
196 | | const curl_uint64_t h01 = 0x0101010101010101LL; |
197 | | x -= (x >> 1) & m1; /* replace every 2 bits with bits present */ |
198 | | x = (x & m2) + ((x >> 2) & m2); /* replace every nibble with bits present */ |
199 | | x = (x + (x >> 4)) & m4; /* replace every byte with bits present */ |
200 | | /* top 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... which makes the |
201 | | * top byte the sum of all individual 8 bytes, throw away the rest */ |
202 | | return (unsigned int)((x * h01) >> 56); |
203 | | } |
204 | | #endif /* CURL_POPCOUNT64_IMPLEMENT */ |
205 | | |
206 | | |
207 | | #ifdef CURL_CTZ64_IMPLEMENT |
208 | | unsigned int Curl_ctz64(curl_uint64_t x) |
209 | | { |
210 | | /* count trailing zeros in a curl_uint64_t. |
211 | | * divide and conquer to find the number of lower 0 bits */ |
212 | | const curl_uint64_t ml32 = 0xFFFFFFFF; /* lower 32 bits */ |
213 | | const curl_uint64_t ml16 = 0x0000FFFF; /* lower 16 bits */ |
214 | | const curl_uint64_t ml8 = 0x000000FF; /* lower 8 bits */ |
215 | | const curl_uint64_t ml4 = 0x0000000F; /* lower 4 bits */ |
216 | | const curl_uint64_t ml2 = 0x00000003; /* lower 2 bits */ |
217 | | unsigned int n; |
218 | | |
219 | | if(!x) |
220 | | return 64; |
221 | | n = 1; |
222 | | if(!(x & ml32)) { |
223 | | n = n + 32; |
224 | | x = x >> 32; |
225 | | } |
226 | | if(!(x & ml16)) { |
227 | | n = n + 16; |
228 | | x = x >> 16; |
229 | | } |
230 | | if(!(x & ml8)) { |
231 | | n = n + 8; |
232 | | x = x >> 8; |
233 | | } |
234 | | if(!(x & ml4)) { |
235 | | n = n + 4; |
236 | | x = x >> 4; |
237 | | } |
238 | | if(!(x & ml2)) { |
239 | | n = n + 2; |
240 | | x = x >> 2; |
241 | | } |
242 | | return n - (unsigned int)(x & 1); |
243 | | } |
244 | | #endif /* CURL_CTZ64_IMPLEMENT */ |