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
							 |