/*
Author:	Martin RobinSon
Project:	No Idea
Idea:		Provide maximum functionnality to the standar ANSI C while using no librairy
			by browsing wikipédia computer science we can see multiple possibility in
			programming that C does not support
How:		By building all necessary logic that is up to the user to add interface
			C syntax provide unsafe memory mannipulation and array , we can exploit
			these way to create all that does not depend on file timer data...
*/

/*
Files:		noidea.mm.c
Function:	get memory management from array, struct, allocation.
Idea:			An array is a memory pointer with a fixed size , can be seen as a portion of
				physical ram , it's possible to use it has a void * pointer while respecting
				it's size limit to give different array size using function like alloc and free
Purpose:		Any device that support C but have no MMU disabling "malloc" and "free" . thus
				still possible to use and array of given size and use it has available size for
				internal dynamic memory allocation. I mean uclinux on microcontroler or pda.
Feature:		the segmentation defragement itself automatiquely by free(). two segment of freed
				memory cannot be aligned without being fusionned has continuous space
lack:			segment protection
function list:
				NOIDEA_segment()		declare your array and its size , give you a memory_struct
				NOIDEA_alloc()			using memory_struct , you can ask memory segment with a size
											if size avalable , give you void* ptr else , give you 0
				NOIDEA_free()			will return given segment to the memory_struct , no need to
											specify the size , it know
*/

#define NULE 0
#define MULE 8888


typedef struct NOIDEA_memory
{
	int id;
	int size;
	struct NOIDEA_memory * last;
	struct NOIDEA_memory * next;
} NOIDEA_memory;

typedef struct NOIDEA_yromem
{
	NOIDEA_memory * space;
	int id;
} NOIDEA_yromem;

/*after reading in wikipedia , i found similarity with Garbage Collection by John McCarthy*/
/*so i've invented nothing*/

/*give an array or a malloc to this function */
NOIDEA_memory * NOIDEA_seg (void * noidea_array, int noidea_size)
{
	if ((noidea_size == 0)||(noidea_array == 0))
	{
		return 0;
	}
	NOIDEA_memory * noidea_header = (NOIDEA_memory*)noidea_array;
	NOIDEA_memory * noidea_new = (NOIDEA_memory*)(noidea_array + sizeof(NOIDEA_memory));
	NOIDEA_yromem * noidea_ender = (NOIDEA_yromem*)(noidea_array + noidea_size - sizeof(NOIDEA_yromem));
	noidea_header->id = MULE;
	noidea_header->size = noidea_size;
	noidea_header->last = noidea_new;
	noidea_header->next = noidea_new;
	noidea_new->id = MULE;
	noidea_new->size = noidea_size - sizeof(NOIDEA_memory);
	noidea_new->last = noidea_header;
	noidea_new->next = noidea_header;
	noidea_ender->space = noidea_header;
	noidea_ender->id = MULE;
	return noidea_header;
}

void * NOIDEA_alloc (NOIDEA_memory * noidea_segment, int noidea_size)
{
	if ((noidea_size == 0)||(noidea_segment == 0))
	{
		return 0;
	}
	if (noidea_size < sizeof(NOIDEA_memory)+sizeof(NOIDEA_yromem))
	{
		noidea_size = sizeof(NOIDEA_memory)+sizeof(NOIDEA_yromem);
	}
	NOIDEA_memory * noidea_pivot = noidea_segment->next;
	NOIDEA_memory * noidea_enogh;
	while (noidea_pivot != noidea_segment)
	{
		if (noidea_pivot->size - sizeof(NOIDEA_memory) > noidea_size + sizeof(int))
		{
			noidea_enogh = noidea_pivot;
			noidea_pivot = noidea_segment->last;
		}
		noidea_pivot = noidea_pivot->next;
	}

	if (noidea_enogh != 0)
	{
		NOIDEA_memory * noidea_mov = (NOIDEA_memory*)((void*)noidea_enogh + noidea_size + sizeof(int));
		NOIDEA_yromem * noidea_set = (NOIDEA_yromem*)((void*)noidea_enogh + noidea_enogh->size - sizeof(NOIDEA_yromem));
		void * noidea_new = (void*) noidea_enogh;

		noidea_mov->id = noidea_enogh->id;
		noidea_mov->size = noidea_enogh->size - noidea_size - sizeof(int);
		noidea_mov->last = noidea_enogh->last;
		noidea_mov->next = noidea_enogh->next;
		noidea_mov->last->next = noidea_mov;
		noidea_mov->next->last = noidea_mov;

		noidea_set->space = noidea_mov;
		*(int*)noidea_new = noidea_size;
		noidea_new = noidea_new +sizeof(int);

		//debug debug debug debug debug debug
		*(int*)noidea_new = 0;
		*(int*)(noidea_new + sizeof(int)) = 0;
		*(int*)(noidea_new + (sizeof(int) * 2)) = 0;
		//debug debug debug debug debug debug

		return noidea_new;
	}
	return NULE;
}

void NOIDEA_free (NOIDEA_memory * noidea_segment, void * noidea_offset)
{

	if ((noidea_segment == 0)||(noidea_offset == 0))
	{
		return ;
	} 
	int noidea_size = *(int*)(noidea_offset - sizeof(int));
	NOIDEA_memory * noidea_new = (NOIDEA_memory*) (noidea_offset - sizeof(int));
	NOIDEA_yromem * noidea_end = (NOIDEA_yromem*) (noidea_offset + noidea_size - sizeof(NOIDEA_yromem));
	noidea_new->id = MULE;
	noidea_new->size = noidea_size + sizeof(int);
	noidea_new->last = noidea_segment;
	noidea_new->next = noidea_segment->next;
	noidea_new->last->next = noidea_new;
	noidea_new->next->last = noidea_new;
	noidea_end->id = MULE;
	noidea_end->space = noidea_new;
	if ((*(int*)(noidea_offset + noidea_size)) == MULE )
	{

		NOIDEA_memory * noidea_forward = (NOIDEA_memory*)(noidea_offset + noidea_size);
		NOIDEA_yromem * noidea_foreend = (NOIDEA_yromem*)((void*)noidea_forward + noidea_forward->size - sizeof(NOIDEA_yromem));
		noidea_new->size = noidea_new->size + noidea_forward->size;
		noidea_forward->next->last = noidea_forward->last;
		noidea_forward->last->next = noidea_forward->next;
		noidea_foreend->space = noidea_new;
		//debug
		noidea_end->id = 0;
		noidea_end->space = 0;
		noidea_forward->id = 0;
		noidea_forward->size = 0;
		noidea_forward->last = 0;
		noidea_forward->next = 0;
		//debug
		noidea_end = noidea_foreend;
	}
	if ((*(int*)(noidea_offset - (sizeof(int)*2))) == MULE )
	{
		NOIDEA_yromem * noidea_backend = (NOIDEA_yromem*)(noidea_offset - (sizeof(int)*2) - sizeof(void*));
		NOIDEA_memory * noidea_bacward = noidea_backend->space;

		noidea_bacward->size = noidea_bacward->size + noidea_new->size;
		noidea_new->next->last = noidea_new->last;
		noidea_new->last->next = noidea_new->next;
		noidea_end->space = noidea_bacward;
		//debug
		noidea_backend->id = 0;
		noidea_backend->space = 0;
		noidea_new->id = 0;
		noidea_new->size = 0;
		noidea_new->last = 0;
		noidea_new->next = 0;
		//debug
		noidea_new = noidea_bacward;
	}
}
