/**********************************************************************
 
	Copyright (C) 2005- Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/

#include	"memory_debug.h"
#include	"memory_routine.h"
#include	"xl.h"
#include	"matrix.h"

#define BASE_TYPE 	int

int mxt_block_get_size(MATRIX_DATA_TYPE *,void * d);
void * mxt_block_sexp2md(int * cpy,struct matrix_data_type*,XL_SEXP * s);
XL_SEXP * mxt_block_md2sexp(struct matrix_data_type*,void * d);
int mxt_block_cmp(struct matrix_data_type*,void*,void*);
void * mxt_alloc_block_data(MATRIX_DATA_TYPE * tp,int atype,
			    void * d,void *w,char*,int);

MATRIX_DATA_TYPE mx_type_block = {
	MDT_BLOCK,
	0,
	mxt_block_get_size,
	mxt_block_sexp2md,
	mxt_block_md2sexp,
	mxt_block_cmp,
	mxt_vector_copy,
	mxt_alloc_copy,
	mxt_alloc_block_data,
	mxt_free_data,
	0,
	0,
	0,
	0,
	mxt_endian_nothing,
	mxt_endian_nothing,
	mxt_convert_basic_to_net,
	mxt_convert_basic_to_host,
	0,0,0,0,0
};





int
mxt_block_get_size(MATRIX_DATA_TYPE * tp,void * d)
{
MATRIX_ALLOC_BLOCK_PARAM * ret;
	ret = (MATRIX_ALLOC_BLOCK_PARAM * )d;
	return ret->size;
}


void * 
mxt_block_sexp2md(int * cpy,struct matrix_data_type* tp,XL_SEXP * s)
{
MATRIX_ALLOC_BLOCK_PARAM * ret;
	switch ( get_type(s) ) {
	case XLT_RAW:
		ret = d_alloc(sizeof(*ret));
		ret->size = s->raw.size;
		ret->block = d_alloc(ret->size);
		memcpy(ret->block,s->raw.data,ret->size);
		if ( cpy )
			*cpy = 1;
		break;
	case XLT_PTR:
		ret = s->ptr.ptr;
		if ( cpy )
			*cpy = 0;
		break;
	default:
		if ( cpy )
			*cpy = 0;
		return 0;
	}
	return ret;
}

XL_SEXP * 
mxt_block_md2sexp(struct matrix_data_type* tp,void * d)
{
	return get_ptr(d,0);
}

int 
mxt_block_cmp(struct matrix_data_type* tp,void* d1,void* d2)
{
MATRIX_ALLOC_BLOCK_PARAM * _d1,* _d2;
unsigned char * p1,* p2;
int sz;
	_d1 = (MATRIX_ALLOC_BLOCK_PARAM*)d1;
	_d2 = (MATRIX_ALLOC_BLOCK_PARAM*)d2;
	if ( _d1->size < _d2->size )
		return -1;
	if ( _d1->size > _d2->size )
		return 1;
	sz = _d1->size;
	p1 = (unsigned char*)_d1->block;
	p2 = (unsigned char*)_d2->block;
	for ( ; sz ; sz -- ) {
		if ( *p1 < *p2 )
			return -1;
		if ( *p1 > *p2 )
			return 1;
		p1 ++;
		p2 ++;
	}
	return 0;
}

void
gc_mtx_block(MATRIX_ALLOC_BLOCK_PARAM * p);

void
gc_mtx_block(MATRIX_ALLOC_BLOCK_PARAM * p)
{
	if ( p == 0 )
		return;
	if ( TEST_AND_SET(p) )
		return;
	gc_text(p->block);
}



void * 
mxt_alloc_block_data(MATRIX_DATA_TYPE * tp,int atype,void * d,void *w,
		     char * __f,int __l)
{
MATRIX_ALLOC_BLOCK_PARAM * p;
MATRIX_ALLOC_BLOCK_PARAM * ret;
	p = (MATRIX_ALLOC_BLOCK_PARAM*)d;
	switch ( atype & MD_TYPE_MASK ) {
	case MD_MALLOC:
		ret = malloc(sizeof(ret));
		break;
	case MD_MMALLOC:
		ret = mmalloc(sizeof(ret),gc_mtx_block);
		break;
	case MD_DALLOC:
		ret = xx_d_alloc(sizeof(ret),__f,__l);
		break;
	case MD_CALLOC:
		ret = mxc_alloc(w,sizeof(ret));
	default:
		er_panic("mxt_alloc_vector");
	}
	*ret = *p;
	ret->h.type = MDT_BLOCK;
	ret->h.dim = 0;
	ret->h.offset = 0;
	if ( atype & MD_NOT_COPY )
		return ret;
	switch ( atype & MD_TYPE_MASK ) {
	case MD_MALLOC:
		ret->block = malloc(ret->size);
		break;
	case MD_MMALLOC:
		ret->block = mmalloc(ret->size,gc_text);
		break;
	case MD_DALLOC:
		ret->block = d_alloc(ret->size);
		break;
	default:
		er_panic("mxt_alloc_vector");
	}
	memcpy(ret->block,p->block,p->size);
	return ret;
}



