From 962f5efdf1af9f07395c28df7a2181733e3e5125 Mon Sep 17 00:00:00 2001 From: bigfoot547 Date: Sat, 3 Feb 2024 16:58:23 -0600 Subject: add lists --- src/htgen.h | 4 +- src/libmain.c | 3 + src/meson.build | 2 +- src/nbt.internal.h | 78 ++++++++++++++++++ src/nbt/list.c | 173 +++++++++++++++++++++++++++++++++++++++ src/nbt/nbt.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++ src/nbt/nbtht.c | 2 + src/nbt/nbtht.internal.h | 44 ++++++++++ 8 files changed, 511 insertions(+), 2 deletions(-) create mode 100644 src/nbt.internal.h create mode 100644 src/nbt/list.c create mode 100644 src/nbt/nbt.c create mode 100644 src/nbt/nbtht.c create mode 100644 src/nbt/nbtht.internal.h (limited to 'src') diff --git a/src/htgen.h b/src/htgen.h index 86bf7e9..3e22329 100644 --- a/src/htgen.h +++ b/src/htgen.h @@ -4,6 +4,7 @@ #include #include +#ifdef HTGEN__TEST_CONFIG #if 1 #define HT_PREFIX shash_ #define HT_VALTYPE char * @@ -75,6 +76,7 @@ XXH64_hash_t ihash_hash_int(int i) #define HT_KEY_FMT "%d" #define HT_VAL_FMT "%d" +#endif #endif #define HT_MALLOC(_sz) malloc(_sz) @@ -128,7 +130,7 @@ HT_VALTYPE HT__NS(popn)(HT__TYPE *ht, HT_KEYTYPE_CREF key, size_t keylen, bool * /* implementations */ -#if defined(HT_IMPLEMENTATIONS) || 1 +#if defined(HT_IMPLEMENTATIONS) #define HT__NODE HT__NS(_node) diff --git a/src/libmain.c b/src/libmain.c index 25a340d..e82635d 100644 --- a/src/libmain.c +++ b/src/libmain.c @@ -5,8 +5,11 @@ #include #define HT_IMPLEMENTATIONS +#define HTGEN__TEST_CONFIG #include "htgen.h" +#include "nbt.h" + #if 1 int main(int argc, char **argv) { shash_t *hash = shash_create(4, 0.75f); diff --git a/src/meson.build b/src/meson.build index a2cf6d0..92fbc23 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1 +1 @@ -libworld_sources = files('libmain.c') +libworld_sources = files('libmain.c', 'nbt/nbt.c', 'nbt/nbtht.c', 'nbt/list.c') diff --git a/src/nbt.internal.h b/src/nbt.internal.h new file mode 100644 index 0000000..88f636b --- /dev/null +++ b/src/nbt.internal.h @@ -0,0 +1,78 @@ +#ifndef LIBWORLD_NBT_INTERNAL_H_INCLUDED +#define LIBWORLD_NBT_INTERNAL_H_INCLUDED + +#include "nbt.h" +#include "nbt/nbtht.internal.h" + +typedef struct { + size_t len; + nbt_byte_t *data; +} nbt__byte_array_t; + +typedef struct { + size_t len; + nbt_int_t *data; +} nbt__int_array_t; + +typedef struct { + size_t len; + nbt_long_t *data; +} nbt__long_array_t; + +typedef struct { + size_t len; + char *data; +} nbt__string_t; + +typedef struct nbt__compound_tag { + nbt__ht_t *hash; +} nbt__compound_t; + +typedef struct nbt__list_tag { + size_t cap, len; + nbt_tag_t **ptags; +} nbt__list_t; + +typedef union { + nbt_byte_t nbt_byte; + nbt_short_t nbt_short; + nbt_int_t nbt_int; + nbt_long_t nbt_long; + + nbt_float_t nbt_float; + nbt_double_t nbt_double; + + nbt__byte_array_t nbt_byte_array; + + nbt__string_t nbt_string; + + nbt__list_t nbt_list; + nbt__compound_t nbt_compound; + + nbt__int_array_t nbt_int_array; + nbt__long_array_t nbt_long_array; +} nbt__any_t; + +struct nbt__tag_tag { + size_t ref; + nbt_type_t type; + nbt__any_t value; +}; + +/* a named tag */ +typedef struct { + nbt_tag_t tag; + + size_t name_length; + char *name; /* nullable if there is no name (will be written as if the name is empty) */ +} nbt__ntag_t; + +#define NBT__CHECK_TYPE(_tag, _t, _r, ...) do { \ + if (!(_tag) || (_tag)->type != _t) { _r(__VA_ARGS__); } \ +} while (0) + +/* functions */ + +void nbt__tag_free(nbt_tag_t *tag); + +#endif /* include guard */ diff --git a/src/nbt/list.c b/src/nbt/list.c new file mode 100644 index 0000000..df12844 --- /dev/null +++ b/src/nbt/list.c @@ -0,0 +1,173 @@ +#include "../nbt.internal.h" +#include "nbt.h" + +#define NBT__RETURN1(_r) return _r +#define NBT__RETURN0() return +#define NBT__CHECK(_tag, _ret) NBT__CHECK_TYPE(_tag, NBT_TAG_LIST, NBT__RETURN1, _ret) +#define NBT__CHECK0(_tag) NBT__CHECK_TYPE(_tag, NBT_TAG_LIST, NBT__RETURN0) + +nbt_type_t nbt_list_type(nbt_tag_t *list) +{ + NBT__CHECK(list, -1); + + if (list->value.nbt_list.len) { + return (*list->value.nbt_list.ptags)->type; + } + + return NBT_TAG_END; +} + +nbt_size_t nbt_list_length(nbt_tag_t *list) +{ + NBT__CHECK(list, (size_t)-1); + return list->value.nbt_list.len; +} + +nbt_tag_t *nbt_list_get(nbt_tag_t *list, nbt_size_t idx) +{ + NBT__CHECK(list, NULL); + + if (list->value.nbt_list.len <= idx) return NULL; + return list->value.nbt_list.ptags[idx]; +} + +#define NBT__APPEND_BODY(_list, _tag, _ex) \ +{ \ + NBT__CHECK(list, -1); \ + if (!tag) return -1; \ + \ + int ret = nbt_list_reserve_more(list, 1); \ + if (ret < 0) return ret; \ + \ + list->value.nbt_list.ptags[list->value.nbt_list.len++] = _ex(tag); \ + return 0; \ +} + +#define NBT__LEAVE_ALONE(_t) _t + +int nbt_list_append(nbt_tag_t *list, nbt_tag_t *tag) + NBT__APPEND_BODY(list, tag, nbt_incref) + +int nbt_list_append_move(nbt_tag_t *list, nbt_tag_t *tag) + NBT__APPEND_BODY(list, tag, NBT__LEAVE_ALONE) + +#define NBT__INSERT_BODY(_list, _tag, _at, _ex) \ +{ \ + NBT__CHECK(list, -1); \ + if (!tag) return -1; \ + \ + int ret = nbt_list_reserve_more(list, 1); \ + if (ret < 0) return ret; \ + \ + memmove(list->value.nbt_list.ptags + _at + 1, \ + list->value.nbt_list.ptags + _at, \ + list->value.nbt_list.len - _at); \ + \ + list->value.nbt_list.ptags[at] = _ex(tag); \ + \ + ++list->value.nbt_list.len; \ + return 0; \ +} + +int nbt_list_insert(nbt_tag_t *list, nbt_tag_t *tag, size_t at) + NBT__INSERT_BODY(list, tag, at, nbt_incref) + +int nbt_list_insert_move(nbt_tag_t *list, nbt_tag_t *tag, size_t at) + NBT__INSERT_BODY(list, tag, at, NBT__LEAVE_ALONE) + +int nbt_list_remove(nbt_tag_t *list, nbt_size_t idx) +{ + nbt_tag_t *ret = nbt_list_pop(list, idx); + if (!ret) return -1; + + nbt_decref(ret); + return 0; +} + +nbt_tag_t *nbt_list_pop(nbt_tag_t *list, nbt_size_t idx) +{ + NBT__CHECK(list, NULL); + if (list->value.nbt_list.len <= idx) return NULL; + + nbt_tag_t *ret = list->value.nbt_list.ptags[idx]; + + --list->value.nbt_list.len; + memmove(list->value.nbt_list.ptags + idx, list->value.nbt_list.ptags + idx + 1, list->value.nbt_list.len - idx); + + return ret; +} + +int nbt_list_remove_back(nbt_tag_t *list) +{ + NBT__CHECK(list, -1); + return nbt_list_remove(list, nbt_list_length(list)); +} + +nbt_tag_t *nbt_list_pop_back(nbt_tag_t *list) +{ + NBT__CHECK(list, NULL); + return nbt_list_pop(list, nbt_list_length(list)); +} + +void nbt_list_clear(nbt_tag_t *list) +{ + NBT__CHECK0(list); + for (size_t n = 0; n < list->value.nbt_list.len; ++n) { + nbt_decref(list->value.nbt_list.ptags[n]); + } + list->value.nbt_list.len = 0; +} + +nbt_size_t nbt_list_capacity(nbt_tag_t *list) +{ + NBT__CHECK(list, (nbt_size_t)-1); + return list->value.nbt_list.cap; +} + +nbt_size_t nbt__list_next_po2(nbt_size_t in) { + nbt_size_t n = 1; + while (n && n < in) n <<= 1; + return n; +} + +int nbt_list_shrink(nbt_tag_t *list) +{ + NBT__CHECK(list, -1); + + if (list->value.nbt_list.len == 0) { + free(list->value.nbt_list.ptags); + list->value.nbt_list.ptags = NULL; + /* a future realloc will allocate a new one */ + return 0; + } else if (list->value.nbt_list.len == list->value.nbt_list.cap) return 0; + + nbt_tag_t **ntags = realloc(list->value.nbt_list.ptags, list->value.nbt_list.len); + if (!ntags) return -1; + list->value.nbt_list.ptags = ntags; + list->value.nbt_list.cap = list->value.nbt_list.len; + + return 0; +} + +int nbt_list_reserve(nbt_tag_t *list, nbt_size_t newsz) +{ + NBT__CHECK(list, -1); + if (newsz <= nbt_list_length(list)) return 0; + + nbt_size_t next = nbt__list_next_po2(newsz); + if (!next) return -1; + if (list->value.nbt_list.cap >= next) return 0; + + nbt_tag_t **ntags = realloc(list->value.nbt_list.ptags, next); + if (!ntags) return -1; + list->value.nbt_list.ptags = ntags; + list->value.nbt_list.cap = next; + + return 0; +} + +int nbt_list_reserve_more(nbt_tag_t *list, nbt_size_t moresz) +{ + NBT__CHECK(list, -1); + return nbt_list_reserve(list, nbt_list_length(list) + moresz); +} diff --git a/src/nbt/nbt.c b/src/nbt/nbt.c new file mode 100644 index 0000000..5948bce --- /dev/null +++ b/src/nbt/nbt.c @@ -0,0 +1,207 @@ +#include "../nbt.internal.h" +#include "nbt.h" +#include "src/nbt.internal.h" + +#include +#include +#include + +nbt_tag_t *nbt__new_val(nbt_type_t type) +{ + nbt_tag_t *tag = calloc(1, sizeof(nbt_tag_t)); + if (!tag) return NULL; + + tag->ref = 1; + tag->type = type; + return tag; +} + +nbt_tag_t *nbt_byte(nbt_byte_t b) +{ + nbt_tag_t *tag = nbt__new_val(NBT_TAG_BYTE); + if (!tag) return NULL; + + tag->value.nbt_byte = b; + return tag; +} + +nbt_tag_t *nbt_short(nbt_short_t s) +{ + nbt_tag_t *tag = nbt__new_val(NBT_TAG_SHORT); + if (!tag) return NULL; + + tag->value.nbt_short = s; + return tag; +} + +nbt_tag_t *nbt_int(nbt_int_t i) +{ + nbt_tag_t *tag = nbt__new_val(NBT_TAG_INT); + if (!tag) return NULL; + + tag->value.nbt_int = i; + return tag; +} + +nbt_tag_t *nbt_long(nbt_long_t l) +{ + nbt_tag_t *tag = nbt__new_val(NBT_TAG_LONG); + if (!tag) return NULL; + + tag->value.nbt_long = l; + return tag; +} + +nbt_tag_t *nbt_float(nbt_float_t f) +{ + nbt_tag_t *tag = nbt__new_val(NBT_TAG_FLOAT); + if (!tag) return NULL; + + tag->value.nbt_float = f; + return tag; +} + +nbt_tag_t *nbt_double(nbt_double_t d) +{ + nbt_tag_t *tag = nbt__new_val(NBT_TAG_DOUBLE); + if (!tag) return NULL; + + tag->value.nbt_byte = d; + return tag; +} + +#define NBT__BUFCOPY_BODY(_tl, _tu, _te, _inbuf, _inlen) \ +{ \ + static nbt_tag_t nbt__single_empty_ ## _tl = { \ + .ref = SIZE_MAX, \ + .type = NBT_TAG_ ## _tu, \ + .value = { .nbt_ ## _tl = { .len = 0, .data = NULL } } \ + }; \ + \ + if (!(_inlen)) return &nbt__single_empty_ ## _tl; \ + \ + nbt_tag_t *tag = nbt__new_val(NBT_TAG_ ## _tu); \ + if (!tag) return NULL; \ + \ + _te *buf = calloc(_inlen, sizeof(_te)); \ + if (!buf) goto cleanup; \ + \ + memcpy(buf, _inbuf, (_inlen) * sizeof(_te)); \ + tag->value.nbt_ ## _tl.len = _inlen; \ + tag->value.nbt_ ## _tl.data = buf; \ + \ + return tag; \ + \ +cleanup: \ + free(tag); \ + return NULL; \ +} + +nbt_tag_t *nbt_byte_array(const nbt_byte_t *bytes, nbt_size_t length) + NBT__BUFCOPY_BODY(byte_array, BYTE_ARRAY, nbt_byte_t, bytes, length) + +nbt_tag_t *nbt_string(const char *c_str) +{ + return nbt_stringn(c_str, strlen(c_str)); +} + +nbt_tag_t *nbt_stringn(const char *c_str, nbt_size_t length) + NBT__BUFCOPY_BODY(string, STRING, char, c_str, length) + +nbt_tag_t *nbt_list(void) +{ + return nbt_listn(0); +} + +nbt_tag_t *nbt_listn(nbt_size_t cap) +{ + nbt_tag_t *tag = nbt__new_val(NBT_TAG_LIST); + if (!tag) return NULL; + if (!cap) cap = 16; + + tag->value.nbt_list.len = 0; + tag->value.nbt_list.cap = cap; + + nbt_tag_t **tags = calloc(cap, sizeof(nbt_tag_t *)); + if (!tags) goto cleanup; + + tag->value.nbt_list.ptags = tags; + + return tag; + +cleanup: + free(tag); + return NULL; +} + +nbt_tag_t *nbt_compound(void) +{ + return nbt_compoundn(0); +} + +nbt_tag_t *nbt_compoundn(nbt_size_t cap) +{ + nbt_tag_t *tag = nbt__new_val(NBT_TAG_COMPOUND); + if (!tag) return NULL; + + tag->value.nbt_compound.hash = nbt__ht_create(cap); + if (!tag->value.nbt_compound.hash) goto cleanup; + + return tag; + +cleanup: + free(tag); + return NULL; +} + +nbt_tag_t *nbt_int_array(const nbt_int_t *ints, nbt_size_t length) + NBT__BUFCOPY_BODY(int_array, INT_ARRAY, nbt_int_t, ints, length) + +nbt_tag_t *nbt_long_array(const nbt_long_t *longs, nbt_size_t length) + NBT__BUFCOPY_BODY(long_array, LONG_ARRAY, nbt_long_t, longs, length); + +void nbt_decref(nbt_tag_t *tag) +{ + if (!tag) return; + if (tag->ref == SIZE_MAX) return; + + --tag->ref; + if (!tag->ref) nbt__tag_free(tag); +} + +nbt_tag_t *nbt_incref(nbt_tag_t *tag) +{ + if (tag->ref != SIZE_MAX) ++tag->ref; + return tag; +} + +void nbt__tag_free(nbt_tag_t *tag) +{ + if (!tag) return; + switch (tag->type) { + case NBT_TAG_BYTE_ARRAY: + free(tag->value.nbt_byte_array.data); + break; + case NBT_TAG_STRING: + free(tag->value.nbt_string.data); + break; + case NBT_TAG_INT_ARRAY: + free(tag->value.nbt_int_array.data); + break; + case NBT_TAG_LONG_ARRAY: + free(tag->value.nbt_long_array.data); + break; + case NBT_TAG_LIST: + nbt_list_clear(tag); + free(tag->value.nbt_list.ptags); + break; + case NBT_TAG_COMPOUND: + nbt_compound_clear(tag); + nbt__ht_free(tag->value.nbt_compound.hash); + break; + default: + break; + } + + free(tag); +} diff --git a/src/nbt/nbtht.c b/src/nbt/nbtht.c new file mode 100644 index 0000000..437a603 --- /dev/null +++ b/src/nbt/nbtht.c @@ -0,0 +1,2 @@ +#define HT_IMPLEMENTATIONS +#include "nbtht.internal.h" diff --git a/src/nbt/nbtht.internal.h b/src/nbt/nbtht.internal.h new file mode 100644 index 0000000..f3bc14b --- /dev/null +++ b/src/nbt/nbtht.internal.h @@ -0,0 +1,44 @@ +#ifndef LIBWORLD_NBTHT_INTERNAL_H_INCLUDED +#define LIBWORLD_NBTHT_INTERNAL_H_INCLUDED + +#include "nbt.h" +#include +#include + +#include + +#define HT_PREFIX nbt__ht_ + +#define HT_VALTYPE nbt_tag_t * +#define HT_VALTYPE_CREF nbt_tag_t * + +#define HT_VAL_SENTINEL NULL +#define HT_VAL_COPY(_v, _sz) nbt_incref(_v) +#define HT_VAL_FREE(_v) nbt_decref(_v) +#define HT_VAL_STATIC_LEN sizeof(nbt_tag_t *) + +inline void *nbt__ht_memdup(const void *in, size_t sz) +{ + void *ret = malloc(sz); + if (!ret) return NULL; + memcpy(ret, in, sz); + return ret; +} + +#define HT_KEYTYPE char * +#define HT_KEYTYPE_CREF const char * +#define HT_KEY_EQ(_val1, _len1, _val2, _len2) (((_len1) == (_len2)) && !memcmp(_val1, _val2, _len1)) +#define HT_KEY_GUESS_LEN(_k) strlen(_k) +#define HT_KEY_FREE(_k) free(_k) +#define HT_KEY_COPY(_k, _klen) nbt__ht_memdup(_k, _klen) + +#define HT_KEY_FMT "%s" +#define HT_VAL_FMT "%p" + +#define HT_HASHTYPE XXH64_hash_t +#define HT_KEY_HASH(_val, _sz) XXH3_64bits(_val, _sz) +#define HT_LOADFACTOR 0.75f + +#include "../htgen.h" + +#endif /* include guard */ -- cgit v1.2.3-70-g09d2