#ifndef ALLOCATOR_C
#define ALLOCATOR_C

#include "types.c"
#include "vector.c"

typedef struct {
  vector_t *storage;
} allocator_storage_t;

allocator_storage_t allocator_storage_create(size_t size) {
  allocator_storage_t a;
  a.storage = vector_create(size);
  return a;
}

void allocator_storage_free_inner_pointers(allocator_storage_t *a) {
#ifdef DEBUG
  printf("allocator_storage_free_inner_pointers | Freeing %zu pointers from "
         "allocator storage\n",
         a->storage->length);
#endif

  size_t size = a->storage->length;
  for (size_t i = 0; i < size; i++) {
    generic_pointer_t p = (generic_pointer_t)(a->storage->data[i]);
    if (p != NULL) {
      free(p);
    }
  }
  vector_destroy(a->storage);
  a->storage = vector_create(size);
}

typedef enum {
  FAILED_TO_ADD_ITEM = -1,
} allocator_storage_error_t;

ssize_t allocator_storage_add(allocator_storage_t *a, generic_pointer_t p) {
  if (p == NULL) {
    return FAILED_TO_ADD_ITEM;
  }

  size_t position = a->storage->length;
  vector_push(a->storage, p);

  return position;
}

void allocator_storage_remove(allocator_storage_t *a, size_t index) {
  vector_pop(a->storage, index);
}

#define ALLOCATOR_STORE(a_ptr, ptr)                                            \
  allocator_storage_add(a_ptr, (generic_pointer_t)ptr);

#define ALLOCATOR_STORE_OR_RETURN(a_ptr, ptr, ...)                             \
  if (ptr == NULL) {                                                           \
    allocator_storage_free_inner_pointers(a_ptr);                              \
    return __VA_ARGS__;                                                        \
  };                                                                           \
  allocator_storage_add(a_ptr, (generic_pointer_t)ptr);

#define ALLOCATOR_RETURN(a_ptr, ...)                                           \
  allocator_storage_free_inner_pointers(a_ptr);                                \
  return __VA_ARGS__;

#endif
