/* # skkinput (Simple Kana-Kanji Input)
 *
 * This file is part of skkinput.
 * Copyright (C) 2002
 * Takashi SAKAMOTO (PXG01715@nifty.ne.jp)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 * 
 * 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.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with skkinput; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#if !defined (tqueue_h)
#define	tqueue_h

#include <string.h>

enum {
	TQUEUE_DEFAULTSIZE	= sizeof (long) / sizeof (unsigned char) * 64,
} ;

typedef struct {
	unsigned char	m_achInternal [TQUEUE_DEFAULTSIZE] ;
	void*			m_pBuffer ;
	int				m_nSize ;
	int				m_nHead ;
	int				m_nTail ;
	int				m_nWidth ;
}	TQueue ;

static inline	Boolean
TQueue_Initialize (
	register TQueue*		pQueue,
	register int			nWidth)
{
	assert (pQueue != NULL) ;
	assert (nWidth > 0) ;

	pQueue->m_nSize		= TQUEUE_DEFAULTSIZE / nWidth ;
	assert (pQueue->m_nSize > 0) ;
	pQueue->m_nHead		= 0 ;
	pQueue->m_nTail		= 0 ;
	pQueue->m_nWidth	= nWidth ;
	pQueue->m_pBuffer	= pQueue->m_achInternal ;
	return	True ;
}

static inline	void
TQueue_Uninitialize (
	register TQueue*		pQueue)
{
	assert (pQueue != NULL) ;

	if (pQueue->m_pBuffer != pQueue->m_achInternal) {
		free (pQueue->m_pBuffer) ;
		pQueue->m_pBuffer	= pQueue->m_achInternal ;
	}
	pQueue->m_nHead		= 0 ;
	pQueue->m_nTail		= 0 ;
	pQueue->m_nWidth	= 1 ;
	pQueue->m_nSize		= TQUEUE_DEFAULTSIZE ;
	return ;
}

static inline	int
TQueue_GetUsage (
	register TQueue*	pQueue)
{
	assert (pQueue != NULL) ;
	return	(pQueue->m_nTail - pQueue->m_nHead) ;
}

static inline	int
TQueue_GetSize (
	register TQueue*	pQueue)
{
	assert (pQueue != NULL) ;
	return	pQueue->m_nSize ;
}

static inline	void*
TQueue_GetData (
	register TQueue*	pQueue)
{
	assert (pQueue != NULL) ;
	return	(unsigned char*)pQueue->m_pBuffer + pQueue->m_nHead * pQueue->m_nWidth ;
}

static inline	void
TQueue_Clear (
	register TQueue*	pQueue)
{
	pQueue->m_nHead	= 0 ;
	pQueue->m_nTail	= 0 ;
	return ;
}

static inline	Boolean
TQueue_In (
	register TQueue*		pQueue,
	register const void*	pValue,
	register int			nValue)
{
	register unsigned char*	pTail ;
	register int			nWidth ;

	assert (pQueue != NULL) ;
	assert (nValue >= 0) ;

	nWidth	= pQueue->m_nWidth ;
	pTail	= (unsigned char*)pQueue->m_pBuffer + pQueue->m_nTail * nWidth ;
	if ((pQueue->m_nTail + nValue) > pQueue->m_nSize) {
		register unsigned char*	pHead ;
		register int			nUsage, nNewSize ;
		register void*			pNewBuffer ;

		nUsage		= pQueue->m_nTail - pQueue->m_nHead ;
		nNewSize	= ((nUsage + nValue) / pQueue->m_nSize + 1) * pQueue->m_nSize ;
		pNewBuffer	= malloc (nNewSize * nWidth) ;
		if (pNewBuffer == NULL)
			return	False ;
		pHead	= (unsigned char*)pQueue->m_pBuffer + pQueue->m_nHead * nWidth ;
		memcpy (pNewBuffer, pHead, nWidth * nUsage) ;
		if (pQueue->m_pBuffer != pQueue->m_achInternal)
			free (pQueue->m_pBuffer) ;
		pQueue->m_pBuffer	= pNewBuffer ;
		pQueue->m_nSize		= nNewSize ;
		pQueue->m_nHead		= 0 ;
		pQueue->m_nTail		= nUsage ;
		pTail				= (unsigned char*) pNewBuffer + nUsage * nWidth ;
	}
	memcpy (pTail, pValue, nValue * nWidth) ;
	pQueue->m_nTail	+= nValue ;
	return	True ;
}

static inline	int
TQueue_Out (
	register TQueue*		pQueue,
	register void*			pDest,
	register int			nDest)
{
    register int			nUsage, nOutput ;
	register unsigned char*	pHead ;

	nUsage	= pQueue->m_nTail - pQueue->m_nHead ;
    if (nDest <= 0 || nUsage <= 0)
		return	0 ;
	pHead	= (unsigned char*)pQueue->m_pBuffer + pQueue->m_nHead * pQueue->m_nWidth ;
	nOutput	= (nDest < nUsage)? nDest : nUsage ;
	if (pDest != NULL)
		memcpy (pDest, pHead, pQueue->m_nWidth * nOutput) ;
	pQueue->m_nHead	+= nOutput ;
	if (pQueue->m_nHead == pQueue->m_nTail) 
		pQueue->m_nHead = pQueue->m_nTail	= 0 ;
	return	nOutput ;
}

#endif


