#pragma once

#include "globals.h"
#include "tools.h"

static inline size_t card_of(void* address)
{
	size_t card = ( ((intptr_t)address) & CARDS_OFFSET_MASK ) >> CARDS_SIZE_EXP;
	checkf(card < CARDS_COUNT, (const char*)"%lu %lu = (%lx & %lx) >> %lu\n", (size_t)CARDS_COUNT, (size_t)card, (size_t)address, (size_t)CARDS_OFFSET_MASK, (size_t)CARDS_SIZE_EXP);
	check(card < CARDS_COUNT);
	return card;
}

struct card_table_t
{
	size_t count;
	void* cards_start[CARDS_COUNT];
};

static inline void ?{}(card_table_t* this)
{
	this->count = 0;
}

static inline void ^?{}(card_table_t* this)
{

}

static inline void* object_at(card_table_t* const this, size_t card_number)
{
	return card_number < this->count ? this->cards_start[card_number] : NULL;
}

static inline void register_object(card_table_t* const this, void* object)
{
	size_t card = card_of(object);
	if(card < this->count)
	{
		intptr_t card_obj_add = (intptr_t)object_at(this, card);
		intptr_t obj_add = (intptr_t)object;
		if(card_obj_add > obj_add)
		{
			this->cards_start[card] = object;
		}
	}
	else
	{
		check(card == this->count);
		this->count++;
		this->cards_start[card] = object;
	}
}

static inline void reset(card_table_t* const this)
{
	for(size_t i = 0; i < this->count; i++)
	{
		this->cards_start[i] = NULL;
	}
	this->count = 0;
}
