d89ef83551
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.
168 lines
6.8 KiB
C
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
|