#pragma once

#ifdef __cforall
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
#ifdef __cforall
}
#endif
#include <fstream.hfa>
#include <vector>

#include "tools.h"

typedef vector(struct gc_memory_pool*, heap_allocator(struct gc_memory_pool*)) pools_table_t;

struct gc_state
{
	bool is_initialized;
	uint8_t from_code;
	struct gc_memory_pool* to_space;
	struct gc_memory_pool* from_space;

	size_t total_space;
	size_t used_space;

	pools_table_t 	pools_table;
	size_t 		pools_table_count;
};

void ctor(gc_state* const state);

void dtor(gc_state* const state);

gc_state* gc_get_state();

static inline bool gc_needs_collect(gc_state* state)
{
	// sout | "Used Space: " | state->used_space | " bytes";
	return state->used_space * 2 > state->total_space;
}

void gc_collect(gc_state* const this);

void* gc_try_allocate(gc_state* const this, size_t size);

void gc_allocate_pool(gc_state* const state);

bool gc_is_in_heap(const gc_state* const state, const void* const address);

bool gc_is_in_to_space(const gc_state* const state, const void* const address);

static inline uint8_t gc_from_space_code(const gc_state *const this)
{
	return this->from_code;
}

struct gc_object_header* gc_get_object_for_ref(gc_state* state, void*);

static inline void gc_register_allocation(gc_state* state, size_t size)
{
	state->used_space += size;
}
