#pragma once

extern "C" {
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
}

#include "tools.h"

#include "card_table.h"
#include "globals.h"
#include "state.h"

struct gc_memory_pool
{
	struct memory_pool* mirror;
	struct memory_pool* next;

	uint8_t type_code;

	card_table_t* cards;

	uint8_t* end_p;
	uint8_t* free_p;
	uint8_t start_p[1];
};

void ?{}(	gc_memory_pool* this,
		size_t size,
		gc_memory_pool* next,
		gc_memory_pool* mirror,
		uint8_t type
	);

void ^?{}(gc_memory_pool* this);

struct gc_pool_object_iterator
{
	struct gc_object_header* object;
	#ifndef NDEBUG
		intptr_t lower_limit;
		intptr_t upper_limit;
	#endif
};


void ?{}( 	gc_pool_object_iterator* this,
		struct gc_object_header* start_object
		#ifndef NDEBUG
			, intptr_t pool_start
			, intptr_t pool_end
		#endif
	);

void ^?{}( gc_pool_object_iterator* this );

bool ?!=?(const gc_pool_object_iterator lhs, const gc_pool_object_iterator rhs);

gc_pool_object_iterator begin(gc_memory_pool* const this);
gc_pool_object_iterator end(gc_memory_pool* const);

gc_pool_object_iterator* ++?(gc_pool_object_iterator* it);

const struct gc_object_header* *?(const gc_pool_object_iterator it);
struct gc_object_header* *?(gc_pool_object_iterator it);

static inline bool gc_pool_is_from_space(const gc_memory_pool* pool)
{
	return gc_from_space_code(gc_get_state()) == pool->type_code;
}

void gc_reset_pool(gc_memory_pool* const pool);

static inline size_t gc_pool_size_used(const gc_memory_pool* pool)
{
	return pool->free_p - pool->start_p;
}

static inline size_t gc_pool_size_total(const gc_memory_pool* pool)
{
	return pool->end_p - pool->start_p;
}

static inline size_t gc_pool_size_left(const gc_memory_pool* pool)
{
	return pool->end_p - pool->free_p;
}

void* gc_pool_allocate(gc_memory_pool* const pool, size_t size, bool zero);

gc_pool_object_iterator gc_pool_iterator_for(gc_memory_pool* const pool, void* member);
