#pragma once

#include <stdbool.h>
#include <stdint.h>

forall(dtype T)
struct gcpointer;

struct gcpointer_t
{
	intptr_t ptr;
	struct gcpointer_t* next;
};

void ?{}(gcpointer_t* this);
void ?{}(gcpointer_t* this, void* address);
void ?{}(gcpointer_t* this, gcpointer_t other);
void ^?{}(gcpointer_t* this);
gcpointer_t ?=?(gcpointer_t* this, gcpointer_t rhs);

//Logical operators
bool gcpointer_equal(gcpointer_t* this, gcpointer_t* rhs);
bool gcpointer_not_equal(gcpointer_t* this, gcpointer_t* rhs);
bool gcpointer_null(const gcpointer_t* this);


#ifndef NDEBUG
	bool is_valid(const gcpointer_t* this);
#endif

forall(dtype T)
struct gcpointer
{
	gcpointer_t internal;
};

//
forall(otype T) void ?{}(gcpointer(T)* this);
forall(otype T) void ?{}(gcpointer(T)* this, void* address);
forall(otype T) void ?{}(gcpointer(T)* this, gcpointer(T) other);
forall(otype T) void ^?{}(gcpointer(T)* this);
forall(otype T) gcpointer(T) ?=?(gcpointer(T)* this, gcpointer(T) rhs);


// forall(otype T) T *?(gcpointer(T) this);
forall(otype T) T* get(gcpointer(T)* this);

//Logical operators
forall(otype T) int ?!=?(gcpointer(T) this, int zero);
forall(otype T) int ?!=?(gcpointer(T) this, gcpointer(T) rhs);
forall(otype T) int ?==?(gcpointer(T) this, gcpointer(T) rhs);
