// Copyright (C) 2004-2009 Christoph Kubisch & Eike Decker
// This file is part of the "Luxinia Engine".
// For conditions of distribution and use, see copyright notice in luxiniapublicsdk.txt
//
// <Author: Christoph Kubisch>
// modelled after Yasli:Vector


#ifndef __LUXCORE_CONTVECTOR_H__
#define __LUXCORE_CONTVECTOR_H__

#include <luxplatform/luxplatform.h>
#include <luxplatform/debug.h>
#include <string.h>

#ifdef __cplusplus
extern "C"{
#endif

	//////////////////////////////////////////////////////////////////////////
	// ContVector
	//	a simple vector implementation (continous memory)
	//	grows allocation as necessary

	#define CONTVECTOR_SMALL	(8)

	typedef struct lxContVector_s{
		ushort		elemsize;
		ushort		alignsize;
		
		byte*		beg;
		byte*		end;
		byte*		eos;
	}lxContVector_t;

	void lxContVector_init(lxContVector_t* cv, uint elemsize);

	// alignsize must be power of 2 and should be >= 4
	// elemsize must be multiple of alignsize
	void lxContVector_initAligned(lxContVector_t* cv, uint elemsize, uint alignsize);
	lxContVector_t lxContVector_new(uint elemsize);
	lxContVector_t lxContVector_copy(lxContVector_t* cv);

	void*	lxContVector_front(lxContVector_t* cv);
	void*	lxContVector_back(lxContVector_t* cv);
	void*	lxContVector_at(lxContVector_t* cv, uint idx);
	int		lxContVector_find(lxContVector_t* cv, void *val);

	uint	lxContVector_elemsize(lxContVector_t *cv);
	uint	lxContVector_capacity(lxContVector_t *cv);
	uint	lxContVector_size(lxContVector_t *cv);
	uint	lxContVector_memuse(lxContVector_t *cv);
	uint	lxContVector_memreserved(lxContVector_t *cv);
	booln	lxContVector_isEmpty(lxContVector_t *cv);

	void	lxContVector_pushBack(lxContVector_t *cv, const void *data);
	void	lxContVector_popBack(lxContVector_t *cv);
	void	lxContVector_clear(lxContVector_t *cv);
	void	lxContVector_makeEmpty(lxContVector_t *cv);

	void	lxContVector_insert(lxContVector_t *cv, uint idx, const void *data);
	void	lxContVector_insertRepeat(lxContVector_t *cv, uint idx, const void *data, uint cnt);
	void	lxContVector_insertMany(lxContVector_t *cv, uint idx, const void *data, uint cnt);
	void	lxContVector_remove(lxContVector_t *cv, uint idx);
	void	lxContVector_removeMany(lxContVector_t *cv, uint idx, uint cnt);
	
	void	lxContVector_shrink(lxContVector_t *cv);
	void	lxContVector_reserve(lxContVector_t *cv,uint cnt);
	void	lxContVector_resize(lxContVector_t *cv,uint cnt, const void *fill);



	LUX_INLINE void lxContVector_init(lxContVector_t* cv, uint elemsize){
		cv->elemsize = elemsize;
		cv->alignsize = 0;
		cv->end = cv->beg;
		cv->eos = cv->beg;
	}
	LUX_INLINE void lxContVector_initAligned(lxContVector_t* cv, uint elemsize, uint alignsize){
		cv->elemsize = elemsize;
		cv->alignsize = alignsize;
		cv->end = cv->beg;
		cv->eos = cv->beg;
	}
	LUX_INLINE lxContVector_t lxContVector_new(uint elemsize){
		lxContVector_t	cv;
		cv.elemsize = elemsize;
#ifdef _DEBUG
		cv.beg = NULL;
		cv.end = NULL;
		cv.eos = NULL;
#else
		cv.end = cv.beg;
		cv.eos = cv.beg;
#endif

		return cv;
	}

	LUX_INLINE uint	lxContVector_elemsize(lxContVector_t *cv){
		return cv->elemsize;
	}
	LUX_INLINE uint	ContVector_memused(lxContVector_t *cv){
		return (uint)(cv->end-cv->beg);
	}
	LUX_INLINE uint	lxContVector_memreserved(lxContVector_t *cv){
		return (uint)(cv->eos-cv->beg);
	}
	LUX_INLINE uint	lxContVector_capacity(lxContVector_t *cv){
		return (uint)((cv->eos-cv->beg)/cv->elemsize);
	}
	LUX_INLINE uint	lxContVector_size(lxContVector_t *cv){
		return (uint)((cv->end-cv->beg)/cv->elemsize);
	}
	LUX_INLINE booln	lxContVector_isEmpty(lxContVector_t *cv){
		return cv->beg == cv->end;
	}
	LUX_INLINE void	lxContVector_makeEmpty(lxContVector_t *cv){
		cv->end = cv->beg;
	}
	LUX_INLINE void*	lxContVector_front(lxContVector_t* cv){
		LUX_ASSERT(!lxContVector_isEmpty(cv));
		return (void*)cv->beg;
	}
	LUX_INLINE void*	lxContVector_back(lxContVector_t* cv){
		LUX_ASSERT(!lxContVector_isEmpty(cv));
		return (void*)(cv->end-cv->elemsize);
	}
	LUX_INLINE void*	lxContVector_at(lxContVector_t* cv, uint idx){
		LUX_ASSERT(!lxContVector_isEmpty(cv) && idx < lxContVector_size(cv));
		return (void*)(cv->beg+(cv->elemsize*idx));
	}
	LUX_INLINE int	lxContVector_find(lxContVector_t* cv, void *val){
		byte* beg = cv->beg;
		while (beg < cv->end){
			if (!memcmp(val,beg,cv->elemsize))
				return (int)((beg-cv->beg)/cv->elemsize);
			beg += cv->elemsize;
		}

		return -1;
	}
	

#ifdef __cplusplus
}
#endif


#endif
