#include <stdlib.h>
#include <string.h>

#include <skipstone/map.h>

skipstone_map *skipstone_map_new() {
    skipstone_map *map;

    if ((map = malloc(SKIPSTONE_MAP_SLOTS * sizeof(*map))) == NULL) {
        goto error_malloc_map;
    }

    memset(map, 0, SKIPSTONE_MAP_SLOTS * sizeof(*map));

    return map;

error_malloc_map:
    return NULL;
}

static void _destroy(skipstone_map *map, void (*destructor)(void *), int depth) {
    uint16_t i;

    for (i=0; i<SKIPSTONE_MAP_SLOTS; i++) {
        if (map[i].next) {
            if (destructor && depth == SKIPSTONE_MAP_DEPTH) {
                destructor(map[i].value);
            } else {
                _destroy(map[i].next, destructor, depth + 1);
            }
        }
    }

    free(map);
}

void skipstone_map_destroy(skipstone_map *map, void (*destructor)(void *)) {
    _destroy(map, destructor, 0);
}

void *skipstone_map_get(skipstone_map *map, uint16_t index) {
    uint16_t i;

    for (i=0; i<SKIPSTONE_MAP_DEPTH; i++) {
        map = map[index & 0xf].next;

        if (map == NULL) {
            return NULL;
        }

        index >>= 4;
    }

    return map[index & 0x0f].value;
}

int skipstone_map_set(skipstone_map *map, uint16_t index, void *value) {
    uint16_t i;

    for (i=0; i<SKIPSTONE_MAP_DEPTH; i++) {
        skipstone_map *next = map[index & 0xf].next;

        if (next == NULL) {
            if ((next = skipstone_map_new()) == NULL) {
                goto error_new;
            }
        }

        map[index & 0xf].next = next;
        map                   = next;

        index >>= 4;
    }

    map[index & 0x0f].value = value;

    return 0;

error_new:
    return -1;
}