use hashmap for compound tag
This commit is contained in:
parent
4760ed147e
commit
85ba301f52
10 changed files with 156 additions and 65 deletions
|
@ -68,7 +68,7 @@ static bool json_print_long_array(const tagdata_t *data, const stream_t *stream)
|
|||
}
|
||||
|
||||
static bool json_print_string(const tagdata_t *data, const stream_t *stream) {
|
||||
if (data->string.size > 1) {
|
||||
if (data->string.size > 0) {
|
||||
if (printi(stream, 0, "\"%.*s\"", data->string.size, data->string.data) == false)
|
||||
return false;
|
||||
} else {
|
||||
|
@ -81,10 +81,14 @@ static bool json_print_string(const tagdata_t *data, const stream_t *stream) {
|
|||
static bool json_print_compound(const tagdata_t *data, const stream_t *stream, int depth) {
|
||||
if (printi(stream, 0, "{\n") == false)
|
||||
return false;
|
||||
for (int32_t i = 0; i < data->compound.size; i++) {
|
||||
if (i != 0 && printi(stream, 0, ",\n") == false)
|
||||
bool first = true;
|
||||
for (uint32_t i = 0; i < data->compound.capacity; i++) {
|
||||
if (data->compound.entries[i].name == NULL)
|
||||
continue;
|
||||
if (!first && printi(stream, 0, ",\n") == false)
|
||||
return false;
|
||||
if (json_print_impl(&data->compound.tags[i], stream, depth + 1) == false)
|
||||
first = false;
|
||||
if (json_print_impl(&data->compound.entries[i], stream, depth + 1) == false)
|
||||
return false;
|
||||
}
|
||||
if (printi(stream, 0, "\n") == false || printi(stream, depth, "}") == false)
|
||||
|
|
|
@ -499,6 +499,9 @@ static bool json_read_list(tagdata_t *data, const stream_t *stream) {
|
|||
|
||||
static bool json_read_compound(tagdata_t *data, const stream_t *stream) {
|
||||
|
||||
map_t map;
|
||||
map_init(&map);
|
||||
|
||||
token_t next = {0};
|
||||
if (json_next_token(&next, stream) == false) {
|
||||
json_token_free(&next);
|
||||
|
@ -506,19 +509,14 @@ static bool json_read_compound(tagdata_t *data, const stream_t *stream) {
|
|||
}
|
||||
|
||||
if (next.type == TOK_RBRACE) {
|
||||
data->compound.tags = NULL;
|
||||
data->compound.size = 0;
|
||||
data->compound = map;
|
||||
return true;
|
||||
}
|
||||
|
||||
int capacity = 8;
|
||||
int len = 0;
|
||||
tag_t *tags = xalloc(capacity * sizeof(tag_t));
|
||||
|
||||
while (1) {
|
||||
|
||||
if (next.type != TOK_STRING) {
|
||||
free(tags);
|
||||
map_free(&map);
|
||||
json_token_free(&next);
|
||||
return false;
|
||||
}
|
||||
|
@ -527,20 +525,20 @@ static bool json_read_compound(tagdata_t *data, const stream_t *stream) {
|
|||
int name_len = next.data.string.len;
|
||||
|
||||
if (name_len < 1) {
|
||||
free(tags);
|
||||
map_free(&map);
|
||||
free(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (json_next_token(&next, stream) == false || next.type != TOK_COLON) {
|
||||
free(tags);
|
||||
map_free(&map);
|
||||
free(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
tag_t value;
|
||||
if (json_read_value(&value, stream, NULL) == false) {
|
||||
free(tags);
|
||||
map_free(&map);
|
||||
free(name);
|
||||
return false;
|
||||
}
|
||||
|
@ -548,42 +546,31 @@ static bool json_read_compound(tagdata_t *data, const stream_t *stream) {
|
|||
value.name = name;
|
||||
value.name_len = name_len;
|
||||
|
||||
if (len == capacity) {
|
||||
capacity *= 2;
|
||||
tags = xrealloc(tags, capacity * sizeof(tag_t));
|
||||
}
|
||||
|
||||
tags[len++] = value;
|
||||
map_put(&map, &value);
|
||||
|
||||
if (json_next_token(&next, stream) == false) {
|
||||
free(tags);
|
||||
free(value.name);
|
||||
map_free(&map);
|
||||
json_token_free(&next);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (next.type == TOK_COMMA) {
|
||||
if (json_next_token(&next, stream) == false) {
|
||||
free(tags);
|
||||
free(name);
|
||||
map_free(&map);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
} else if (next.type == TOK_RBRACE) {
|
||||
break;
|
||||
} else {
|
||||
free(tags);
|
||||
free(value.name);
|
||||
map_free(&map);
|
||||
json_token_free(&next);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data->compound.tags = xalloc(len * sizeof(tag_t));
|
||||
data->compound.size = len;
|
||||
memcpy(data->compound.tags, tags, len * sizeof(tag_t));
|
||||
free(tags);
|
||||
data->compound = map;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
__attribute__((__noreturn__))
|
||||
static void die() {
|
||||
|
@ -36,6 +37,12 @@ void *xalloc(size_t amount) {
|
|||
return res;
|
||||
}
|
||||
|
||||
void *xzalloc(size_t amount) {
|
||||
void *res = xalloc(amount);
|
||||
memset(res, 0, sizeof(amount));
|
||||
return res;
|
||||
}
|
||||
|
||||
void *xrealloc(void *ptr, size_t amount) {
|
||||
void *res = realloc(ptr, amount);
|
||||
if (res == NULL)
|
||||
|
|
|
@ -9,4 +9,5 @@ __attribute__((__noreturn__, format(printf, 1, 2)))
|
|||
void perror_and_die(char *format, ...);
|
||||
|
||||
void *xalloc(size_t amount);
|
||||
void *xzalloc(size_t amount);
|
||||
void *xrealloc(void *ptr, size_t amount);
|
||||
|
|
86
src/map.c
Normal file
86
src/map.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include "map.h"
|
||||
#include "lib.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void map_init(map_t *map) {
|
||||
map->len = 0;
|
||||
map->capacity = 0;
|
||||
map->entries = NULL;
|
||||
}
|
||||
|
||||
void map_free(map_t *map) {
|
||||
if (map->entries == NULL)
|
||||
return;
|
||||
for (uint32_t i = 0; i < map->capacity; i++) {
|
||||
if (map->entries[i].name != NULL)
|
||||
tag_free(&map->entries[i]);
|
||||
}
|
||||
free(map->entries);
|
||||
}
|
||||
|
||||
static uint32_t hash(const char *name, uint16_t len) {
|
||||
uint32_t hash = 2166136261u;
|
||||
while(len > 0) {
|
||||
hash ^= (uint8_t)(*name);
|
||||
hash *= 16777619;
|
||||
name++;
|
||||
len--;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static tag_t *map_find(tag_t *entries, uint32_t capacity, tag_t *tag) {
|
||||
uint32_t index = hash(tag->name, tag->name_len) % capacity;
|
||||
while(true) {
|
||||
tag_t *entry = &entries[index];
|
||||
if (entry->name == NULL) {
|
||||
return entry;
|
||||
} else if (
|
||||
entry->name_len == tag->name_len &&
|
||||
memcmp(entry->name, tag->name, tag->name_len) == 0
|
||||
) {
|
||||
return entry;
|
||||
}
|
||||
index += 1;
|
||||
index %= capacity;
|
||||
}
|
||||
}
|
||||
|
||||
static void map_grow(map_t *map, uint32_t capacity) {
|
||||
tag_t *entries = xzalloc(capacity * sizeof(tag_t));
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
entries[i].name = NULL;
|
||||
entries[i].name_len = 0;
|
||||
}
|
||||
map->len = 0;
|
||||
for (uint32_t i = 0; i < map->capacity; i++) {
|
||||
tag_t *tag = &map->entries[i];
|
||||
if (tag->name == NULL) continue;
|
||||
|
||||
tag_t *dest = map_find(entries, capacity, tag);
|
||||
*dest = *tag;
|
||||
map->len++;
|
||||
}
|
||||
free(map->entries);
|
||||
|
||||
map->entries = entries;
|
||||
map->capacity = capacity;
|
||||
}
|
||||
|
||||
void map_put(map_t *map, tag_t *tag) {
|
||||
if (map->len + 1 > map->capacity * 0.75) {
|
||||
int capacity = (map->capacity == 0 ? 8 : (2 * map->capacity));
|
||||
map_grow(map, capacity);
|
||||
}
|
||||
tag_t *dest = map_find(map->entries, map->capacity, tag);
|
||||
if (dest->name == NULL) {
|
||||
map->len++;
|
||||
} else {
|
||||
tag_free(dest);
|
||||
}
|
||||
*dest = *tag;
|
||||
}
|
15
src/map.h
Normal file
15
src/map.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct tag_t tag_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t len;
|
||||
uint32_t capacity;
|
||||
tag_t *entries;
|
||||
} map_t;
|
||||
|
||||
void map_init(map_t *map);
|
||||
void map_free(map_t *map);
|
||||
void map_put(map_t *map, tag_t *tag);
|
|
@ -64,9 +64,11 @@ static bool nbt_print_list(const tagdata_t *data, const stream_t *stream) {
|
|||
}
|
||||
|
||||
static bool nbt_print_compound(const tagdata_t *data, const stream_t *stream) {
|
||||
for (int32_t i = 0; i < data->compound.size; i++)
|
||||
if (nbt_print(&data->compound.tags[i], stream) == false)
|
||||
for (uint32_t i = 0; i < data->compound.capacity; i++) {
|
||||
if (data->compound.entries[i].name == NULL) continue;
|
||||
if (nbt_print(&data->compound.entries[i], stream) == false)
|
||||
return false;
|
||||
}
|
||||
if (stream_write_i8(stream, TAG_END) == false)
|
||||
return false;
|
||||
return true;
|
||||
|
|
|
@ -118,44 +118,36 @@ static bool nbt_read_list(tagdata_t *data, const stream_t *stream) {
|
|||
}
|
||||
|
||||
static bool nbt_read_compound(tagdata_t *data, const stream_t *stream) {
|
||||
int32_t size = 0;
|
||||
int32_t capacity = 8;
|
||||
tag_t *tags = xalloc(capacity * sizeof(tag_t));
|
||||
|
||||
map_t map;
|
||||
map_init(&map);
|
||||
|
||||
while (1) {
|
||||
|
||||
tag_t tag;
|
||||
|
||||
if (nbt_read_header(&tag, stream, true) == false) {
|
||||
free(tags);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tag.name_len < 1) {
|
||||
free(tags);
|
||||
map_free(&map);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tag.type == TAG_END)
|
||||
break;
|
||||
|
||||
if (nbt_read_data(&tag, stream) == false) {
|
||||
free(tags);
|
||||
if (tag.name_len < 1) {
|
||||
map_free(&map);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size == capacity) {
|
||||
capacity *= 2;
|
||||
tags = xrealloc(tags, capacity * sizeof(tag_t));
|
||||
if (nbt_read_data(&tag, stream) == false) {
|
||||
map_free(&map);
|
||||
return false;
|
||||
}
|
||||
|
||||
tags[size++] = tag;
|
||||
map_put(&map, &tag);
|
||||
}
|
||||
|
||||
data->compound.size = size;
|
||||
data->compound.tags = xalloc(size * sizeof(tag_t));
|
||||
memcpy(data->compound.tags, tags, size * sizeof(tag_t));
|
||||
free(tags);
|
||||
data->compound = map;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "tag.h"
|
||||
#include "map.h"
|
||||
#include "nbt/nbt.h"
|
||||
#include "json/json.h"
|
||||
|
||||
|
@ -28,9 +29,7 @@ void tag_free(tag_t *tag) {
|
|||
free(tag->data.list.tags);
|
||||
break;
|
||||
case TAG_COMPOUND:
|
||||
for (int32_t i = 0; i < tag->data.compound.size; i++)
|
||||
tag_free(&tag->data.compound.tags[i]);
|
||||
free(tag->data.compound.tags);
|
||||
map_free(&tag->data.compound);
|
||||
break;
|
||||
case TAG_INT_ARRAY:
|
||||
free(tag->data.i_arr.data);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "stream.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -46,10 +47,7 @@ typedef union {
|
|||
int32_t size;
|
||||
struct tag_t *tags;
|
||||
} list;
|
||||
struct {
|
||||
int32_t size;
|
||||
struct tag_t *tags;
|
||||
} compound;
|
||||
map_t compound;
|
||||
struct {
|
||||
int32_t size;
|
||||
int32_t *data;
|
||||
|
|
Loading…
Reference in a new issue