/*****
 FILE
 	cmemory.m - source code for CMemory class
 VERSION
	$Id$
 CHANGELOG
 	$Log$
 */

#include <coconut/cmemory.h>
#include <coconut/cmemalloc.h>
#include <coconut/cpagealloc.h>
#include <coconut/csystem.h>

@implementation CMemory

- init
{
	id <PAllocator>	alloc = [[CMemAlloc alloc] init] ;
	g_return_val_if_fail(alloc != nil, nil) ;
	return [self initMemory: alloc] ;
}

- initMemoryWithPage: (size_t) unit
{
	id <PAllocator>	alloc = [[CPageAlloc alloc] initPageAlloc: unit] ;
	g_return_val_if_fail(alloc != nil, nil) ;
	return [self initMemory: alloc] ;
}

- initMemory: (id <PAllocator>) alloc
{
	mem_allocator = alloc ;
	mem_ptr = NULL ; mem_size = 0 ;
	return [super init] ;
}

- (void) dealloc
{
	[mem_allocator free: mem_ptr] ;
	[mem_allocator release] ;
	[super dealloc] ;
}

- (void *) new: (size_t) reqsize
{
	[mem_allocator free: mem_ptr] ;
	mem_ptr = [mem_allocator allocate: mem_size = reqsize] ;
	return mem_ptr ;
}

- (void *) copy: (const void *) src size: (size_t) size
{
	[mem_allocator free: mem_ptr] ;
	mem_ptr = [mem_allocator allocate: mem_size = size] ;
	g_return_val_if_fail(mem_ptr != NULL, NULL) ;
	memmove(mem_ptr, src, size) ;
	return mem_ptr ;
}

- (void *) changeSize: (size_t) newsize
{
	mem_ptr = [mem_allocator reallocate: mem_ptr size: mem_size = newsize] ;
	return mem_ptr ;
}

- (void *) increaseSize: (size_t) delta
{
	mem_ptr = [mem_allocator reallocate: mem_ptr size: mem_size += delta] ;
	return mem_ptr ;
}

- (void *) decreaseSize: (size_t) delta
{
	mem_size = mem_size > delta ? mem_size - delta : 0 ;
	mem_ptr = [mem_allocator reallocate: mem_ptr size: mem_size] ;
	return mem_ptr ;
}

- (void *) ptr
{
	return mem_ptr ;
}

- (size_t) size
{
	return mem_size ;
}

- (void *) append: (const void *) src size: (size_t) size
{
	size_t	orgsize = mem_size ;
	if(src == NULL || size == 0)
		return mem_ptr ;
	mem_ptr = [mem_allocator reallocate: mem_ptr size: mem_size += size] ;
	g_return_val_if_fail(mem_ptr != NULL, NULL) ;
	memmove(&mem_ptr[orgsize], src, size) ;
	return mem_ptr ;
}

- (void *) prepend: (const void *) src size: (size_t) size
{
	size_t	orgsize = mem_size ;
	if(src == NULL || size == 0)
		return mem_ptr ;
	mem_ptr = [mem_allocator reallocate: mem_ptr size: mem_size += size] ;
	g_return_val_if_fail(mem_ptr != NULL, NULL) ;
	memmove(&mem_ptr[size], mem_ptr, orgsize) ;
	memmove(mem_ptr, src, size) ;
	return mem_ptr ;
}

- (void *) insert: (u_int) pos src: (const void *) src size: (size_t) size
{
	size_t	orgsize = mem_size ;
	if(src == NULL || size == 0 || mem_size < pos)
		return mem_ptr ;
	if(pos == mem_size)
		return [self append: src size: size] ;
	else if(pos == 0)
		return [self prepend: src size: size] ;
	mem_ptr = [mem_allocator reallocate: mem_ptr size: mem_size += size] ;
	g_return_val_if_fail(mem_ptr != NULL, NULL) ;
	memmove(&mem_ptr[pos+size], &mem_ptr[pos], orgsize - pos) ;
	memmove(&mem_ptr[pos], src, size) ;
	return mem_ptr ;
}

- (void *) remove: (u_int) frompos size: (size_t) size
{	
	u_int	rest ;

	/*****
	  012345 	... frompos = 2, size = 3
	    ^^^ */
	if(mem_ptr == NULL || mem_size <= frompos || size == 0)
		return mem_ptr ;
	/* if frompos+size > mem_size, size = mem_size - frompos */
	if(frompos+size > mem_size)
		size = mem_size - frompos ;
	rest = mem_size - frompos - size ;
	memmove(&mem_ptr[frompos], &mem_ptr[frompos+size], rest) ;
	mem_ptr = [mem_allocator reallocate: mem_ptr size: mem_size -= size] ;
	return mem_ptr ;
}

- clear
{
	[mem_allocator free: mem_ptr] ;
	mem_ptr = NULL ; mem_size = 0 ;
	return nil ;
}

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

	newalloc = [mem_allocator duplicate] ;
	newmem = [[CMemory alloc] initMemory: newalloc] ;
	g_return_val_if_fail(newmem != nil, nil) ;

	if(mem_ptr){
		[newmem copy: mem_ptr size: mem_size] ;
	}
	return newmem ;
}

- setAlreadyAllocated: (void *) src size: (size_t) size
{
	[mem_allocator free: mem_ptr] ;
	mem_ptr = src ; mem_size = size ;
	return nil ;
}

@end

