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/list.c | |
| parent | fix using the wrong free function (diff) | |
add lists
Diffstat (limited to 'src/nbt/list.c')
| -rw-r--r-- | src/nbt/list.c | 173 |
1 files changed, 173 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);
+}
|
