mirror of
				https://github.com/MarioSpore/Grinch-AP.git
				synced 2025-10-21 20:21:32 -06:00 
			
		
		
		
	 acf85eb9ab
			
		
	
	acf85eb9ab
	
	
	
		
			
			* Speedups: remove dependency on c++ * Speedups: intset: handle malloc failing * Speedups: intset: fix corner case for int64 on 32bit systems original idea was to only use bucket->val if int<pointer, but we always have a union now anyway * Speedups: add size comment to player_set bucket configuration * test: more tests for LocationStore.find_item * test: require _speedups in CI This kind of tests that the build succeeds. * test: even more tests for LocationStore.find_item * Speedups: intset uniform comment style * Speedups: intset: avoid memory leak when realloc fails * Speedups: intset: make `gcc -pedantic -std=c99 -fanalyzer` without warnings Unnamed unions are not in C99, this got fixed. The overhead of setting count=0 is minimal or optimized-out and silences -fanalizer (see comment). * Speedups: don't leak memory in case of exception * Speedups: intset: validate alloc and free This won't happen in our cython, but it's still a good addition. * CI: add test framework for C/C++ code * CI: ctest: fix cwd * Speedups: intset: ignore msvc warning * Tests: intset: revert attempt at no-asan We solve this with env vars in ctest now, and this fails for msvc. * Test: cpp: docs: fix typo * Test: cpp: docs: fix another typo * Test: intset: proper bucket count for Negative test INTxx_MIN % 1 would not produce a negative number, so the test was flawed.
		
			
				
	
	
		
			136 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* A specialized unordered_set implementation for literals, where bucket_count
 | |
|  * is defined at initialization rather than increased automatically.
 | |
|  */
 | |
| #include <stddef.h>
 | |
| #include <stdbool.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #ifndef INTSET_NAME
 | |
| #error "Please #define INTSET_NAME ... before including intset.h"
 | |
| #endif
 | |
| 
 | |
| #ifndef INTSET_TYPE
 | |
| #error "Please #define INTSET_TYPE ... before including intset.h"
 | |
| #endif
 | |
| 
 | |
| /* macros to generate unique names from INTSET_NAME */
 | |
| #ifndef INTSET_CONCAT
 | |
| #define INTSET_CONCAT_(a, b) a ## b
 | |
| #define INTSET_CONCAT(a, b) INTSET_CONCAT_(a, b)
 | |
| #define INTSET_FUNC_(a, b) INTSET_CONCAT(a, _ ## b)
 | |
| #endif
 | |
| 
 | |
| #define INTSET_FUNC(name) INTSET_FUNC_(INTSET_NAME, name)
 | |
| #define INTSET_BUCKET INTSET_CONCAT(INTSET_NAME, Bucket)
 | |
| #define INTSET_UNION INTSET_CONCAT(INTSET_NAME, Union)
 | |
| 
 | |
| #if defined(_MSC_VER)
 | |
| #pragma warning(push)
 | |
| #pragma warning(disable : 4200)
 | |
| #endif
 | |
| 
 | |
| 
 | |
| typedef struct {
 | |
|     size_t count;
 | |
|     union INTSET_UNION {
 | |
|         INTSET_TYPE val;
 | |
|         INTSET_TYPE *data;
 | |
|     } v;
 | |
| } INTSET_BUCKET;
 | |
| 
 | |
| typedef struct {
 | |
|     size_t bucket_count;
 | |
|     INTSET_BUCKET buckets[];
 | |
| } INTSET_NAME;
 | |
| 
 | |
| static INTSET_NAME *INTSET_FUNC(new)(size_t buckets)
 | |
| {
 | |
|     size_t i, size;
 | |
|     INTSET_NAME *set;
 | |
| 
 | |
|     if (buckets < 1)
 | |
|         buckets = 1;
 | |
|     if ((SIZE_MAX - sizeof(INTSET_NAME)) / sizeof(INTSET_BUCKET) < buckets)
 | |
|         return NULL;
 | |
|     size = sizeof(INTSET_NAME) + buckets * sizeof(INTSET_BUCKET);
 | |
|     set = (INTSET_NAME*)malloc(size);
 | |
|     if (!set)
 | |
|         return NULL;
 | |
|     memset(set, 0, size); /* gcc -fanalyzer does not understand this sets all buckets' count to 0 */
 | |
|     for (i = 0; i < buckets; i++) {
 | |
|         set->buckets[i].count = 0;
 | |
|     }
 | |
|     set->bucket_count = buckets;
 | |
|     return set;
 | |
| }
 | |
| 
 | |
| static void INTSET_FUNC(free)(INTSET_NAME *set)
 | |
| {
 | |
|     size_t i;
 | |
|     if (!set)
 | |
|         return;
 | |
|     for (i = 0; i < set->bucket_count; i++) {
 | |
|         if (set->buckets[i].count > 1)
 | |
|             free(set->buckets[i].v.data);
 | |
|     }
 | |
|     free(set);
 | |
| }
 | |
| 
 | |
| static bool INTSET_FUNC(contains)(INTSET_NAME *set, INTSET_TYPE val)
 | |
| {
 | |
|     size_t i;
 | |
|     INTSET_BUCKET* bucket = &set->buckets[(size_t)val % set->bucket_count];
 | |
|     if (bucket->count == 1)
 | |
|         return bucket->v.val == val;
 | |
|     for (i = 0; i < bucket->count; ++i) {
 | |
|         if (bucket->v.data[i] == val)
 | |
|             return true;
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| static bool INTSET_FUNC(add)(INTSET_NAME *set, INTSET_TYPE val)
 | |
| {
 | |
|     INTSET_BUCKET* bucket;
 | |
| 
 | |
|     if (INTSET_FUNC(contains)(set, val))
 | |
|         return true; /* ok */
 | |
| 
 | |
|     bucket = &set->buckets[(size_t)val % set->bucket_count];
 | |
|     if (bucket->count == 0) {
 | |
|         bucket->v.val = val;
 | |
|         bucket->count = 1;
 | |
|     } else if (bucket->count == 1) {
 | |
|         INTSET_TYPE old = bucket->v.val;
 | |
|         bucket->v.data = (INTSET_TYPE*)malloc(2 * sizeof(INTSET_TYPE));
 | |
|         if (!bucket->v.data) {
 | |
|             bucket->v.val = old;
 | |
|             return false; /* error */
 | |
|         }
 | |
|         bucket->v.data[0] = old;
 | |
|         bucket->v.data[1] = val;
 | |
|         bucket->count = 2;
 | |
|     } else {
 | |
|         size_t new_bucket_size;
 | |
|         INTSET_TYPE* new_bucket_data;
 | |
| 
 | |
|         new_bucket_size = (bucket->count + 1) * sizeof(INTSET_TYPE);
 | |
|         new_bucket_data = (INTSET_TYPE*)realloc(bucket->v.data, new_bucket_size);
 | |
|         if (!new_bucket_data)
 | |
|             return false; /* error */
 | |
|         bucket->v.data = new_bucket_data;
 | |
|         bucket->v.data[bucket->count++] = val;
 | |
|     }
 | |
|     return true; /* success */
 | |
| }
 | |
| 
 | |
| 
 | |
| #if defined(_MSC_VER)
 | |
| #pragma warning(pop)
 | |
| #endif
 | |
| 
 | |
| #undef INTSET_FUNC
 | |
| #undef INTSET_BUCKET
 | |
| #undef INTSET_UNION
 |