/*****
 NAME
	cpagealloc.m - source code for CPageAlloc class
 VERSION
	$Id$
 CHANGELOG
	$Log$
 */

#include <coconut/cpagealloc.h>
#include <coconut/cmemalloc.h>
#include <coconut/csystem.h>
#include <stdlib.h>
#include <string.h>

#define	DEF_PAGE_SIZE		256

typedef	struct {
	size_t	page_size ;
} header_t ;

#define	SET_HEADER(PTR, PAGE) \
	do { \
		((header_t *) PTR)->page_size = PAGE ; \
	} while(0)

static const size_t	HEADSIZE = ALIGNED_SIZE(sizeof(header_t)) ;

#define	HEAD2PTR(PTR)	(void *) (((byte *) PTR) + HEADSIZE)
#define	PTR2HEAD(PTR)	(header_t *) (((byte *) PTR) - HEADSIZE)

@implementation CPageAlloc

- init
{
	unit_size = DEF_PAGE_SIZE ;
	return [super init] ;
}

- initPageAlloc: (size_t) size
{
	unit_size = size ;
	return [super init] ;
}

- (void) dealloc
{
	[super dealloc] ;
}

- (void *) allocate: (size_t) reqsize
{
	size_t	pagesize ;
	void *	page ;

	pagesize = PAGE_SIZE(reqsize, unit_size) ;
	page = [CMemAlloc allocate: HEADSIZE + pagesize] ;
	SET_HEADER(page, pagesize) ;
	return HEAD2PTR(page) ;
}

- (void *) reallocate: (void *) src size: (size_t) reqsize
{
	header_t *	head ;
	void *		page ;
	size_t		pagesize ;
	size_t		smallsize ;

	if(src == NULL)
		return [self allocate: reqsize] ;
	head = PTR2HEAD(src) ;
	pagesize = head->page_size ; smallsize = pagesize - unit_size ;
	if(smallsize <= reqsize && reqsize <= pagesize)
		return src ;
	pagesize = PAGE_SIZE(reqsize, unit_size) ;
	page = [CMemAlloc reallocate: head size: HEADSIZE + pagesize] ;
	SET_HEADER(page, pagesize) ;
	return HEAD2PTR(page) ;
}

- free: (void *) src
{
	if(src)
		[CMemAlloc free: PTR2HEAD(src)] ;
	return nil ;
}

- (id <PAllocator>) duplicate
{
	id <PAllocator>	newalloc ;

	newalloc = [[CPageAlloc alloc] initPageAlloc: unit_size] ;
	[CSystem checkPtr: newalloc] ;
	return newalloc ;
}

@end

