#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); }