diff options
| author | 2024-02-03 16:58:23 -0600 | |
|---|---|---|
| committer | 2024-02-03 22:26:55 -0600 | |
| commit | 962f5efdf1af9f07395c28df7a2181733e3e5125 (patch) | |
| tree | 790bd875d37d6f2a78bf93eb35e4dd11718f6379 /src/nbt | |
| parent | fix using the wrong free function (diff) | |
add lists
Diffstat (limited to 'src/nbt')
| -rw-r--r-- | src/nbt/list.c | 173 | ||||
| -rw-r--r-- | src/nbt/nbt.c | 207 | ||||
| -rw-r--r-- | src/nbt/nbtht.c | 2 | ||||
| -rw-r--r-- | src/nbt/nbtht.internal.h | 44 |
4 files changed, 426 insertions, 0 deletions
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 <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 <string.h>
+#include <stdlib.h>
+
+#include <xxh3.h>
+
+#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 */
|
