clay/src/clay-map.h
Gwendolyn d89ef83551 Reworked property system completely.
Properties can now have values of different types, and they are registered with their name, either to a layout class or globally.
Layout classes are also registered with their name.
2023-02-08 01:09:21 +01:00

168 lines
6.8 KiB
C

#ifndef CLAY_CLAY_MAP_H
#define CLAY_CLAY_MAP_H
#ifndef __GNUC__
#error "this requires GCC" // todo: make clang-compatible if possible
#endif
#include <stdbool.h>
#include <stddef.h>
#include "clay-list.h"
#include "cmoball.h"
#ifndef CLAY_MAP_DEFAULT_INITIAL_SIZE
# define CLAY_MAP_DEFAULT_INITIAL_SIZE 16
#endif
#define CLAY_MAP_TYPE(map_type$name, map_type$key_type, map_type$value_type) \
typedef struct { \
map_type$key_type key; \
map_type$value_type value; \
} map_type$name ## _entry_s, *map_type$name ## _entry; \
typedef int (* map_type$name ## _compare_fn)(map_type$key_type, map_type$key_type); \
typedef struct { \
map_type$name ## _entry_s *elements; \
size_t length; \
size_t size; \
map_type$name ## _compare_fn compare_fn; \
} map_type$name ## _s, *map_type$name; \
typedef const map_type$name ## _s * map_type$name ## _const;
#define CLAY_STRING_MAP_TYPE(map_type$name, map_type$value_type) CLAY_MAP_TYPE(map_type$name, const char *, map_type$value_type)
#define CLAY_MAP_FOREACH(map_foreach$map, map_foreach$key, map_foreach$valueptr) \
for (int map_foreach$next = 1; map_foreach$next; (map_foreach$next = 0)) \
for (size_t map_foreach$i = 0; map_foreach$next && map_foreach$i < (map_foreach$map)->length; ++map_foreach$i) \
for (typeof((map_foreach$map)->elements) map_foreach$el = &(map_foreach$map)->elements[map_foreach$i]; map_foreach$next; ({ break; })) \
for (typeof(map_foreach$el->key) map_foreach$key = map_foreach$el->key; map_foreach$next; ({ break; })) \
for (typeof(map_foreach$el->value) *map_foreach$valueptr = &map_foreach$el->value; map_foreach$next;) \
for (; !(map_foreach$next = 0); ({map_foreach$next = 1;break;}))
#define clay_map_init(map$, map$initial_size) clay_list_init((map$), (map$initial_size))
// note: map$type is never in parantheses in the substitution, because it is a type and not an expression!
#define clay_map_create_1(map$type) clay_map_create_default_cmp(map$type, CLAY_MAP_DEFAULT_INITIAL_SIZE)
#define clay_map_create_2(map$type, map$size_or_cmp) _Generic((map$size_or_cmp), int: clay_map_create_default_cmp(map$type, (size_t)(map$size_or_cmp)), default: clay_map_create_3(map$type, CLAY_MAP_DEFAULT_INITIAL_SIZE, (void*)(map$size_or_cmp)))
#define clay_map_create_default_cmp(map$type, map$size) clay_map_create_3(map$type, map$size, ({ map$type map$dummy; _Generic(map$dummy->elements->key, const char *: strcmp, default: NULL);}))
#define clay_map_create_3(map$type, map$size, map$cmp) ({ \
assert((map$size) > 0); \
map$type map$map = malloc(sizeof(*map$map)); \
clay_map_init(map$map, (map$size)); \
map$map->compare_fn = map$cmp; \
map$map; \
})
#define clay_map_create(...) CMOBALL(clay_map_create, __VA_ARGS__)
CLAY_MAP_TYPE(some_map, int, int)
CLAY_STRING_MAP_TYPE(other_map, int)
#define clay_map_empty(map$) free((map$)->elements)
#define clay_map_destroy(map$) ({ \
clay_map_empty(map$); \
free(map$); \
})
#define clay_map_set(map_set$map, map_set$key, map_set$value) ({ \
bool map_set$found = false; \
CLAY_LIST_FOREACH((map_set$map), map_set$el, map_set$_) { \
if (((map_set$map)->compare_fn == NULL && map_set$el->key == map_set$key) || \
((map_set$map)->compare_fn != NULL && (map_set$map)->compare_fn(map_set$el->key, (map_set$key)) == 0)) { \
map_set$el->value = (map_set$value); \
map_set$found = true; \
break; \
} \
} \
if (!map_set$found) { \
typeof(*(map_set$map)->elements) map_set$el = {.key = (map_set$key), .value = (map_set$value)}; \
clay_list_append((map_set$map), map_set$el); \
} \
})
#define clay_map_get(map_get$map, map_get$key, map_get$value) ({ \
bool map_get$found = false; \
CLAY_LIST_FOREACH((map_get$map), map_get$el, map_get$_) { \
if (((map_get$map)->compare_fn == NULL && map_get$el->key == (map_get$key)) || \
((map_get$map)->compare_fn != NULL && (map_get$map)->compare_fn(map_get$el->key, (map_get$key)) == 0)) { \
*(map_get$value) = map_get$el->value; \
map_get$found = true; \
break; \
} \
} \
map_get$found; \
})
#define clay_map_get_ptr(map_get$map, map_get$key, map_get$value) ({ \
bool map_get$found = false; \
CLAY_LIST_FOREACH((map_get$map), map_get$el, map_get$_) { \
if (((map_get$map)->compare_fn == NULL && map_get$el->key == (map_get$key)) || \
((map_get$map)->compare_fn != NULL && (map_get$map)->compare_fn(map_get$el->key, (map_get$key)) == 0)) { \
*(map_get$value) = &map_get$el->value; \
map_get$found = true; \
break; \
} \
} \
map_get$found; \
})
#define clay_map_get_default(map_get$map, map_get$key, map_get$default) ({ \
typeof((map_get$map)->elements->value) map_get$value = map_get$default; \
CLAY_LIST_FOREACH((map_get$map), map_get$el, map_get$_) { \
if (((map_get$map)->compare_fn == NULL && map_get$el->key == (map_get$key)) || \
((map_get$map)->compare_fn != NULL && (map_get$map)->compare_fn(map_get$el->key, (map_get$key)) == 0)) { \
map_get$value = map_get$el->value; \
break; \
} \
} \
map_get$value; \
})
#define clay_map_has_key(map_has_key$map, map_has_key$key) ({ \
bool map_has_key$found = false; \
CLAY_LIST_FOREACH((map_has_key$map), map_has_key$el, map_has_key$) { \
if (((map_has_key$map)->compare_fn == NULL && map_has_key$el->key == (map_has_key$key)) || \
((map_has_key$map)->compare_fn != NULL && (map_has_key$map)->compare_fn(map_has_key$el->key, (map_has_key$key)) == 0)) { \
map_has_key$found = true; \
break; \
} \
} \
map_has_key$found; \
})
#define clay_map_remove(map_remove$map, map_remove$key) ({ \
bool map_remove$found = false; \
CLAY_LIST_FOREACH((map_remove$map), map_remove$el, map_remove$idx) { \
if (((map_remove$map)->compare_fn == NULL && map_remove$el->key == (map_remove$key)) || \
((map_remove$map)->compare_fn != NULL && (map_remove$map)->compare_fn(map_remove$el->key, (map_remove$key)) == 0)) { \
clay_list_remove((map_remove$map), map_remove$idx); \
map_remove$found = true; \
} \
} \
map_remove$found; \
})
#define clay_map_clone(map_clone$map) ({ \
typeof(map_clone$map) map_clone$map_new = clay_map_create(typeof(map_clone$map), (map_clone$map)->length); \
memcpy(map_clone$map_new->elements, (map_clone$map)->elements, (map_clone$map)->length * sizeof(*map_clone$map_new->elements)); \
map_clone$map_new->length = (map_clone$map)->length; \
map_clone$map_new->compare_fn = (map_clone$map)->compare_fn; \
map_clone$map_new; \
})
#endif //CLAY_CLAY_MAP_H