💾 Archived View for gmi.noulin.net › gitRepositories › set › file › set.h.gmi captured on 2023-01-29 at 13:15:34. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
set.h (11844B)
1 2 #include "libsheepyObject.h" 3 4 // TODO 5 // add and remove 6 // buckets with multiple keys 7 8 /** 9 * simple static set 10 * 11 * keys are assigned a unique index 12 * this data structure maps keys to indexes in an array of size count 13 * 14 * when there is a collision, a linear search is done until an empty bucket is found 15 * 16 * the simple static set can be used together with a bitset to filter keys efficiently 17 * 18 * HASHFUNC, ISEMPTY and CMPFUNC are functions defined before using sstaticSet* macros 19 * 20 * hashType HASHFUNC(key); 21 * returns the hash value for key 22 * 23 * bool ISEMPTY(keyInSet); 24 * returns true when the bucket don't have a key 25 * 26 * bool CMPFUNC(key1, key2); 27 * returns true when key1 is equal key2 28 */ 29 30 /** type definition */ 31 #define sstaticSetT(typeName, keyType, count)\ 32 typedef struct { keyType set[count];} typeName; 33 34 /** clear set */ 35 #define sstaticSetClear(name) memset((name)->set, 0, sizeof((name)->set)); 36 37 /** get bucket at index */ 38 #define sstaticSetAt(name, index) ((name)->set[index]) 39 40 /** 41 * add key to set 42 * 43 * \return 44 * 1 key is added 45 * 0 key was already in set 46 * -1 set is full, can't add the key 47 */ 48 #define sstaticSetAdd(name, key) ({\ 49 var UNIQVAR(k) = key;\ 50 var UNIQVAR(hash) = HASHFUNC(UNIQVAR(k));\ 51 size_t UNIQVAR(mhash) = UNIQVAR(hash) % ARRAY_SIZE((name)->set);\ 52 i8 UNIQVAR(r) = -1;\ 53 if (ISEMPTY((name)->set[UNIQVAR(mhash)])) {\ 54 /* save key in this bucket */\ 55 /*logI("empty");*/\ 56 (name)->set[UNIQVAR(mhash)] = UNIQVAR(k);\ 57 UNIQVAR(r) = 1;\ 58 }\ 59 else {\ 60 /* key already in set or collision */\ 61 UNIQVAR(r) = 0;\ 62 if (not CMPFUNC((name)->set[UNIQVAR(mhash)], UNIQVAR(k))) {\ 63 /* collision */\ 64 /*logI("collision");*/\ 65 circular(UNIQVAR(i), UNIQVAR(mhash), ARRAY_SIZE((name)->set)) {\ 66 /*logI("circ %zu %d", UNIQVAR(i), (name)->set[UNIQVAR(i)]);*/\ 67 if (CMPFUNC((name)->set[UNIQVAR(i)], UNIQVAR(k))) {\ 68 goto UNIQVAR(end);\ 69 }\ 70 if (ISEMPTY((name)->set[UNIQVAR(i)])) {\ 71 /* use empty bucket for key */\ 72 (name)->set[UNIQVAR(i)] = UNIQVAR(k);\ 73 UNIQVAR(r) = 1;\ 74 /*logI("found a bucket");*/\ 75 goto UNIQVAR(end);\ 76 }\ 77 } /* circular */\ 78 /* set is full, the key cannot be added */\ 79 UNIQVAR(r) = -1;\ 80 } /* if (not CPMFUNC((name)->set[UNIQVAR(mhash)], UNIQVAR(k))) */\ 81 }\ 82 UNIQVAR(end):\ 83 UNIQVAR(r);\ 84 }) 85 86 #define sstaticSetHas(name, key) ({\ 87 var UNIQVAR(k) = key;\ 88 var UNIQVAR(hash) = HASHFUNC(UNIQVAR(k));\ 89 size_t UNIQVAR(mhash) = UNIQVAR(hash) % ARRAY_SIZE((name)->set);\ 90 bool UNIQVAR(r) = true;\ 91 if (not CMPFUNC((name)->set[UNIQVAR(mhash)], UNIQVAR(k))) {\ 92 /* collision */\ 93 /*logI("collision");*/\ 94 circular(UNIQVAR(i), UNIQVAR(mhash), ARRAY_SIZE((name)->set)) {\ 95 /*logI("circ %zu %d", UNIQVAR(i), (name)->set[UNIQVAR(i)]);*/\ 96 if (CMPFUNC((name)->set[UNIQVAR(i)], UNIQVAR(k))) {\ 97 /* found key in set */\ 98 /*logI("already key");*/\ 99 goto UNIQVAR(end);\ 100 }\ 101 if (ISEMPTY((name)->set[UNIQVAR(i)])) {\ 102 /* key not found */\ 103 /*logI("found a bucket");*/\ 104 break;\ 105 }\ 106 } /* circular */\ 107 UNIQVAR(r) = false;\ 108 } /* if (not CPMFUNC((name)->set[UNIQVAR(mhash)], UNIQVAR(k))) */\ 109 UNIQVAR(end):\ 110 UNIQVAR(r);\ 111 }) 112 113 /** 114 * get index for key 115 * 116 * \return 117 * index for key 118 * -1 not found 119 */ 120 #define sstaticSetGet(name, key) ({\ 121 var UNIQVAR(k) = key;\ 122 var UNIQVAR(hash) = HASHFUNC(UNIQVAR(k));\ 123 ssize_t UNIQVAR(r) = UNIQVAR(hash) % ARRAY_SIZE((name)->set);\ 124 if (not CMPFUNC((name)->set[UNIQVAR(r)], UNIQVAR(k))) {\ 125 /* collision */\ 126 /*logI("collision");*/\ 127 circular(UNIQVAR(i), UNIQVAR(r), ARRAY_SIZE((name)->set)) {\ 128 /*logI("circ %zu %d", UNIQVAR(i), (name)->set[UNIQVAR(i)]);*/\ 129 if (CMPFUNC((name)->set[UNIQVAR(i)], UNIQVAR(k))) {\ 130 /* found key in set */\ 131 /*logI("already key");*/\ 132 UNIQVAR(r) = UNIQVAR(i);\ 133 goto UNIQVAR(end);\ 134 }\ 135 if (ISEMPTY((name)->set[UNIQVAR(i)])) {\ 136 /* key not found */\ 137 /*logI("found a bucket");*/\ 138 break;\ 139 }\ 140 } /* circular */\ 141 UNIQVAR(r) = -1;\ 142 } /* if (not CPMFUNC((name)->set[UNIQVAR(r)], UNIQVAR(k))) */\ 143 UNIQVAR(end):\ 144 UNIQVAR(r);\ 145 }) 146 147 /** 148 * get index and add key 149 * 150 * \return 151 * index for key 152 * -1 set is full, can't add the key 153 */ 154 #define sstaticSetGetNAdd(name, key) ({\ 155 var UNIQVAR(k) = key;\ 156 var UNIQVAR(hash) = HASHFUNC(UNIQVAR(k));\ 157 ssize_t UNIQVAR(r) = UNIQVAR(hash) % ARRAY_SIZE((name)->set);\ 158 if (ISEMPTY((name)->set[UNIQVAR(r)])) {\ 159 /* save key in this bucket */\ 160 /*logI("empty");*/\ 161 (name)->set[UNIQVAR(r)] = UNIQVAR(k);\ 162 }\ 163 else {\ 164 /* key already in set or collision */\ 165 if (not CMPFUNC((name)->set[UNIQVAR(r)], UNIQVAR(k))) {\ 166 /* collision */\ 167 /*logI("collision");*/\ 168 circular(UNIQVAR(i), UNIQVAR(r), ARRAY_SIZE((name)->set)) {\ 169 /*logI("circ %zu %d", UNIQVAR(i), (name)->set[UNIQVAR(i)]);*/\ 170 if (CMPFUNC((name)->set[UNIQVAR(i)], UNIQVAR(k))) {\ 171 /* found key in set */\ 172 UNIQVAR(r) = UNIQVAR(i);\ 173 /*logI("already key");*/\ 174 goto UNIQVAR(end);\ 175 }\ 176 if (ISEMPTY((name)->set[UNIQVAR(i)])) {\ 177 /* use empty bucket for key */\ 178 (name)->set[UNIQVAR(i)] = UNIQVAR(k);\ 179 UNIQVAR(r) = UNIQVAR(i);\ 180 /*logI("found a bucket");*/\ 181 goto UNIQVAR(end);\ 182 }\ 183 } /* circular */\ 184 UNIQVAR(r) = -1;\ 185 } /* if (not CPMFUNC((name)->set[UNIQVAR(r)], UNIQVAR(k))) */\ 186 }\ 187 UNIQVAR(end):\ 188 UNIQVAR(r);\ 189 }) 190 191 192 193 /** 194 * another static set 195 * 196 * this set doesn't need ISFUNC, it keeps track of empty buckets 197 */ 198 199 /** type definition */ 200 #define astaticSetT(typeName, keyType, count)\ 201 staticBitsetT(UNIQVAR(bits), u64, count);\ 202 typedef struct { \ 203 keyType set[count];\ 204 UNIQVAR(bits) hasKey;\ 205 } typeName; 206 207 /** clear set */ 208 #define astaticSetClear(name) do{\ 209 memset((name)->set, 0, sizeof((name)->set));\ 210 staticBitsetClear(&(name)->hasKey);\ 211 } while(0) 212 213 /** get bucket at index */ 214 #define astaticSetAt(name, index) ((name)->set[index]) 215 216 /** is bucket empty */ 217 #define astaticSetIsBucketEmpty(name, index) !staticBitsetGet(&(name)->hasKey, index) 218 219 /** 220 * add key to set 221 * 222 * \return 223 * 1 key is added 224 * 0 key was already in set 225 * -1 set is full, can't add the key 226 */ 227 #define astaticSetAdd(name, key) ({\ 228 var UNIQVAR(k) = key;\ 229 var UNIQVAR(hash) = HASHFUNC(UNIQVAR(k));\ 230 size_t UNIQVAR(mhash) = UNIQVAR(hash) % ARRAY_SIZE((name)->set);\ 231 i8 UNIQVAR(r) = -1;\ 232 if (astaticSetIsBucketEmpty(name,UNIQVAR(mhash))) {\ 233 /* save key in this bucket */\ 234 /*logI("empty");*/\ 235 (name)->set[UNIQVAR(mhash)] = UNIQVAR(k);\ 236 UNIQVAR(r) = 1;\ 237 staticBitset1(&(name)->hasKey, UNIQVAR(mhash));\ 238 }\ 239 else {\ 240 /* key already in set or collision */\ 241 UNIQVAR(r) = 0;\ 242 if (not CMPFUNC((name)->set[UNIQVAR(mhash)], UNIQVAR(k))) {\ 243 /* collision */\ 244 /*logI("collision");*/\ 245 circular(UNIQVAR(i), UNIQVAR(mhash), ARRAY_SIZE((name)->set)) {\ 246 /*logI("circ %zu %d", UNIQVAR(i), (name)->set[UNIQVAR(i)]);*/\ 247 if (CMPFUNC((name)->set[UNIQVAR(i)], UNIQVAR(k))) {\ 248 goto UNIQVAR(end);\ 249 }\ 250 if (astaticSetIsBucketEmpty(name,UNIQVAR(i))) {\ 251 /* use empty bucket for key */\ 252 (name)->set[UNIQVAR(i)] = UNIQVAR(k);\ 253 UNIQVAR(r) = 1;\ 254 staticBitset1(&(name)->hasKey, UNIQVAR(i));\ 255 /*logI("found a bucket");*/\ 256 goto UNIQVAR(end);\ 257 }\ 258 } /* circular */\ 259 /* set is full, the key cannot be added */\ 260 UNIQVAR(r) = -1;\ 261 } /* if (not CPMFUNC((name)->set[UNIQVAR(mhash)], UNIQVAR(k))) */\ 262 }\ 263 UNIQVAR(end):\ 264 UNIQVAR(r);\ 265 }) 266 267 #define astaticSetHas(name, key) ({\ 268 var UNIQVAR(k) = key;\ 269 var UNIQVAR(hash) = HASHFUNC(UNIQVAR(k));\ 270 size_t UNIQVAR(mhash) = UNIQVAR(hash) % ARRAY_SIZE((name)->set);\ 271 bool UNIQVAR(r) = true;\ 272 if (not CMPFUNC((name)->set[UNIQVAR(mhash)], UNIQVAR(k))) {\ 273 /* collision */\ 274 /*logI("collision");*/\ 275 circular(UNIQVAR(i), UNIQVAR(mhash), ARRAY_SIZE((name)->set)) {\ 276 /*logI("circ %zu %d", UNIQVAR(i), (name)->set[UNIQVAR(i)]);*/\ 277 if (CMPFUNC((name)->set[UNIQVAR(i)], UNIQVAR(k))) {\ 278 /* found key in set */\ 279 /*logI("already key");*/\ 280 goto UNIQVAR(end);\ 281 }\ 282 if (astaticSetIsBucketEmpty(name,UNIQVAR(i))) {\ 283 /* key not found */\ 284 /*logI("found a bucket");*/\ 285 break;\ 286 }\ 287 } /* circular */\ 288 UNIQVAR(r) = false;\ 289 } /* if (not CPMFUNC((name)->set[UNIQVAR(mhash)], UNIQVAR(k))) */\ 290 UNIQVAR(end):\ 291 UNIQVAR(r);\ 292 }) 293 294 /** 295 * get index for key 296 * 297 * \return 298 * index for key 299 * -1 not found 300 */ 301 #define astaticSetGet(name, key) ({\ 302 var UNIQVAR(k) = key;\ 303 var UNIQVAR(hash) = HASHFUNC(UNIQVAR(k));\ 304 ssize_t UNIQVAR(r) = UNIQVAR(hash) % ARRAY_SIZE((name)->set);\ 305 if (not CMPFUNC((name)->set[UNIQVAR(r)], UNIQVAR(k))) {\ 306 /* collision */\ 307 /*logI("collision");*/\ 308 circular(UNIQVAR(i), UNIQVAR(r), ARRAY_SIZE((name)->set)) {\ 309 /*logI("circ %zu %d", UNIQVAR(i), (name)->set[UNIQVAR(i)]);*/\ 310 if (CMPFUNC((name)->set[UNIQVAR(i)], UNIQVAR(k))) {\ 311 /* found key in set */\ 312 /*logI("already key");*/\ 313 UNIQVAR(r) = UNIQVAR(i);\ 314 goto UNIQVAR(end);\ 315 }\ 316 if (astaticSetIsBucketEmpty(name,UNIQVAR(i))) {\ 317 /* key not found */\ 318 /*logI("found a bucket");*/\ 319 break;\ 320 }\ 321 } /* circular */\ 322 UNIQVAR(r) = -1;\ 323 } /* if (not CPMFUNC((name)->set[UNIQVAR(r)], UNIQVAR(k))) */\ 324 UNIQVAR(end):\ 325 UNIQVAR(r);\ 326 }) 327 328 /** 329 * get index and add key 330 * 331 * \return 332 * index for key 333 * -1 set is full, can't add the key 334 */ 335 #define astaticSetGetNAdd(name, key) ({\ 336 var UNIQVAR(k) = key;\ 337 var UNIQVAR(hash) = HASHFUNC(UNIQVAR(k));\ 338 ssize_t UNIQVAR(r) = UNIQVAR(hash) % ARRAY_SIZE((name)->set);\ 339 if (astaticSetIsBucketEmpty(name,UNIQVAR(r))) {\ 340 /* save key in this bucket */\ 341 /*logI("empty");*/\ 342 (name)->set[UNIQVAR(r)] = UNIQVAR(k);\ 343 staticBitset1(&(name)->hasKey, UNIQVAR(r));\ 344 }\ 345 else {\ 346 /* key already in set or collision */\ 347 if (not CMPFUNC((name)->set[UNIQVAR(r)], UNIQVAR(k))) {\ 348 /* collision */\ 349 /*logI("collision");*/\ 350 circular(UNIQVAR(i), UNIQVAR(r), ARRAY_SIZE((name)->set)) {\ 351 /*logI("circ %zu %d", UNIQVAR(i), (name)->set[UNIQVAR(i)]);*/\ 352 if (CMPFUNC((name)->set[UNIQVAR(i)], UNIQVAR(k))) {\ 353 /* found key in set */\ 354 UNIQVAR(r) = UNIQVAR(i);\ 355 /*logI("already key");*/\ 356 goto UNIQVAR(end);\ 357 }\ 358 if (astaticSetIsBucketEmpty(name,UNIQVAR(i))) {\ 359 /* use empty bucket for key */\ 360 (name)->set[UNIQVAR(i)] = UNIQVAR(k);\ 361 UNIQVAR(r) = UNIQVAR(i);\ 362 staticBitset1(&(name)->hasKey, UNIQVAR(i));\ 363 /*logI("found a bucket");*/\ 364 goto UNIQVAR(end);\ 365 }\ 366 } /* circular */\ 367 UNIQVAR(r) = -1;\ 368 } /* if (not CPMFUNC((name)->set[UNIQVAR(r)], UNIQVAR(k))) */\ 369 }\ 370 UNIQVAR(end):\ 371 UNIQVAR(r);\ 372 }) 373 374 // vim: set expandtab ts=2 sw=2: