From 962f5efdf1af9f07395c28df7a2181733e3e5125 Mon Sep 17 00:00:00 2001 From: bigfoot547 Date: Sat, 3 Feb 2024 16:58:23 -0600 Subject: add lists --- src/nbt/list.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 src/nbt/list.c (limited to 'src/nbt/list.c') 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); +} -- cgit v1.2.3-70-g09d2