371 lines
9.2 KiB
C++
371 lines
9.2 KiB
C++
#ifndef _CIRCUITQUEUE_H_
|
|
#define _CIRCUITQUEUE_H_
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
|
|
//=============================================================================================================================
|
|
/// 원형 큐 클래스 템플릿
|
|
//=============================================================================================================================
|
|
template<typename T>
|
|
class CircuitQueue
|
|
{
|
|
public:
|
|
CircuitQueue() : m_pData( NULL ), m_nLength( 0 ), m_nSize( 0 ), m_nHead( 0 ), m_nTail( 0 )
|
|
{
|
|
InitializeCriticalSection( &m_cs );
|
|
}
|
|
|
|
virtual ~CircuitQueue()
|
|
{
|
|
if( m_pData ) delete [] m_pData;
|
|
DeleteCriticalSection( &m_cs );
|
|
}
|
|
|
|
//=============================================================================================================================
|
|
/**
|
|
@remarks
|
|
큐를 생성한다.
|
|
@param nSize
|
|
큐 사이즈
|
|
@param nExtraSize
|
|
패킷이 버퍼 뒤쪽에서 앞쪽으로 나누어 들어갈 때 패킷을 이어주기 위해 확보할
|
|
버퍼 뒤쪽 여분의 메모리 크기(실제 여분 메모리 = sizeof(T) * nExtraSize )
|
|
*/
|
|
//=============================================================================================================================
|
|
void Create( int nSize, int nExtraSize = 0 )
|
|
{
|
|
EnterCriticalSection( &m_cs );
|
|
if( m_pData ) delete [] m_pData;
|
|
|
|
m_pData = new T[nSize + nExtraSize];
|
|
m_nSize = nSize;
|
|
m_nExtraSize = nExtraSize;
|
|
LeaveCriticalSection( &m_cs );
|
|
}
|
|
|
|
//=============================================================================================================================
|
|
/**
|
|
@remarks
|
|
큐를 청소한다.
|
|
*/
|
|
//=============================================================================================================================
|
|
inline void Clear()
|
|
{
|
|
EnterCriticalSection( &m_cs );
|
|
|
|
m_nLength = 0;
|
|
m_nHead = 0;
|
|
m_nTail = 0;
|
|
|
|
LeaveCriticalSection( &m_cs );
|
|
}
|
|
|
|
/// 큐의 남은 공간을 리턴한다.
|
|
inline int GetSpace()
|
|
{
|
|
int iRet;
|
|
|
|
EnterCriticalSection( &m_cs );
|
|
iRet = m_nSize - m_nLength;
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/// 현재 사용중인 큐의 크기를 리턴한다.
|
|
inline int GetLength()
|
|
{
|
|
int iRet;
|
|
|
|
EnterCriticalSection( &m_cs );
|
|
iRet = m_nLength;
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/// 최대 버퍼 사이즈를 리턴한다.
|
|
inline int GetMaxLength()
|
|
{
|
|
int iRet;
|
|
|
|
EnterCriticalSection( &m_cs );
|
|
iRet = m_nSize;
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/// 데이터가 큐 뒤쪽으로 꽉 차서 앞으로 이어지는 경우, 뒤쪽 끝까지의 데이터 개수를 리턴한다.
|
|
inline int GetBackDataCount()
|
|
{
|
|
int iRet;
|
|
|
|
EnterCriticalSection( &m_cs );
|
|
iRet = m_nSize - m_nHead;
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/// 데이터를 읽을 포인터(Head)를 리턴한다.
|
|
inline T* GetReadPtr()
|
|
{
|
|
T *pRet;
|
|
|
|
EnterCriticalSection( &m_cs );
|
|
pRet = m_pData + m_nHead;
|
|
|
|
// 만약 버퍼 맨 뒤쪽 데이터를 읽으려는 경우 여분의 버퍼에 적절히 복사해준다.
|
|
int nSplitFirstDataCount;
|
|
if( m_nHead > m_nTail && ( nSplitFirstDataCount = m_nSize - m_nHead ) < m_nExtraSize )
|
|
{
|
|
memcpy( m_pData + m_nSize, m_pData, sizeof(T) * ( m_nExtraSize - nSplitFirstDataCount ) );
|
|
}
|
|
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return pRet;
|
|
}
|
|
|
|
/// 데이터를 쓸 포인터(Tail)를 리턴한다.
|
|
inline T* GetWritePtr()
|
|
{
|
|
T *pRet;
|
|
|
|
EnterCriticalSection( &m_cs );
|
|
pRet = m_pData + m_nTail;
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return pRet;
|
|
}
|
|
|
|
/// 잘리지 않고 한번에 읽을 수 있는 길이를 리턴한다.
|
|
inline int GetReadableLen()
|
|
{
|
|
int iRet;
|
|
|
|
EnterCriticalSection( &m_cs );
|
|
if( m_nHead == m_nTail ) iRet = GetLength() > 0 ? m_nSize - m_nHead: 0;
|
|
else if( m_nHead < m_nTail ) iRet = m_nTail - m_nHead;
|
|
else iRet = m_nSize - m_nHead;
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/// 잘리지 않고 한번에 쓰기 가능한 길이를 리턴한다.
|
|
inline int GetWritableLen()
|
|
{
|
|
int iRet;
|
|
|
|
EnterCriticalSection( &m_cs );
|
|
if( m_nHead == m_nTail ) iRet = GetLength() > 0 ? 0 : m_nSize - m_nTail;
|
|
else if( m_nHead < m_nTail ) iRet = m_nSize - m_nTail;
|
|
else iRet = m_nHead - m_nTail;
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return iRet;
|
|
}
|
|
|
|
//=============================================================================================================================
|
|
/**
|
|
@remarks
|
|
큐에 데이터를 넣는다.
|
|
@param pSrc
|
|
큐에 삽입할 데이터 포인터
|
|
@param nSize
|
|
큐에 삽입할 데이터의 길이
|
|
@retval BOOL
|
|
정상적으로 데이터 삽입이 끝나면 TRUE를 리턴한다.
|
|
큐가 꽉차서 삽입할 수 없는 경우 FALSE를 리턴한다.
|
|
*/
|
|
//=============================================================================================================================
|
|
inline BOOL Enqueue( T *pSrc, int nSize )
|
|
{
|
|
EnterCriticalSection( &m_cs );
|
|
|
|
if( GetSpace() < nSize )
|
|
{
|
|
LeaveCriticalSection( &m_cs );
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
// 데이터가 나누어져 두번에 카피되는 경우인가?
|
|
BOOL bCopyToExtraBuffer = ( ( m_nHead <= m_nTail ) && ( m_nSize - m_nTail < nSize ) );
|
|
*/
|
|
|
|
// pSrc가 NULL인 경우 데이터 큐잉 없이 tail과 length만 갱신한다.
|
|
if( pSrc )
|
|
{
|
|
if( m_nHead <= m_nTail )
|
|
{
|
|
// 1. head가 tail보다 앞에 있는 경우
|
|
int nBackSpaceCount = m_nSize - m_nTail;
|
|
|
|
if( nBackSpaceCount >= nSize )
|
|
{
|
|
// 뒤쪽에 남은 공간이 복사할 양보다 같거나 큰 경우 한번에 복사한다.
|
|
memcpy( m_pData + m_nTail, pSrc, sizeof(T) * nSize );
|
|
}
|
|
else
|
|
{
|
|
// 뒤쪽에 남은 공간이 복사할 양보다 작은 경우 두번에 나누어 복사한다.
|
|
memcpy( m_pData + m_nTail, pSrc, sizeof(T) * nBackSpaceCount );
|
|
memcpy( m_pData, pSrc + nBackSpaceCount, sizeof(T) * ( nSize - nBackSpaceCount ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 2. head가 tail보다 뒤에 있는 경우
|
|
memcpy( m_pData + m_nTail, pSrc, sizeof(T) * nSize );
|
|
}
|
|
}
|
|
|
|
/*
|
|
if( bCopyToExtraBuffer )
|
|
{
|
|
// 뒤쪽의 잘린 데이터를 여분의 버퍼에도 복사해준다.
|
|
memcpy( m_pData + m_nSize, pSrc + m_nSize - m_nTail, sizeof(T) * ( nSize - ( m_nSize - m_nTail ) ) );
|
|
}
|
|
*/
|
|
|
|
m_nTail += nSize;
|
|
m_nTail %= m_nSize;
|
|
m_nLength += nSize;
|
|
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//=============================================================================================================================
|
|
/**
|
|
@remarks
|
|
큐에서 데이터를 꺼낸다.
|
|
@param pTar
|
|
큐에서 꺼낸 데이터를 복사할 버퍼의 포인터
|
|
@param nSize
|
|
큐에서 꺼낼 데이터 길이
|
|
@retval BOOL
|
|
정상적으로 데이터를 꺼내면 TRUE를 리턴한다.
|
|
꺼낼 데이터가 nSize보다 적은 경우 FALSE를 리턴한다.
|
|
*/
|
|
//=============================================================================================================================
|
|
inline BOOL Dequeue( T *pTar, int nSize )
|
|
{
|
|
EnterCriticalSection( &m_cs );
|
|
|
|
if( !Peek( pTar, nSize ) )
|
|
{
|
|
LeaveCriticalSection( &m_cs );
|
|
return FALSE;
|
|
}
|
|
|
|
m_nHead += nSize;
|
|
m_nHead %= m_nSize;
|
|
m_nLength -= nSize;
|
|
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//=============================================================================================================================
|
|
/**
|
|
@remarks
|
|
큐에서 데이터를 꺼내지 않고 복사만 해온다.
|
|
@param pTar
|
|
큐의 데이터를 복사할 버퍼의 포인터
|
|
@param nSize
|
|
큐에서 복사할 데이터 길이
|
|
@retval BOOL
|
|
정상적으로 데이터를 복사하면 TRUE를 리턴한다.
|
|
꺼낼 데이터가 nSize보다 적은 경우 FALSE를 리턴한다.
|
|
*/
|
|
//=============================================================================================================================
|
|
inline BOOL Peek( T *pTar, int nSize )
|
|
{
|
|
EnterCriticalSection( &m_cs );
|
|
|
|
if( m_nLength < nSize )
|
|
{
|
|
LeaveCriticalSection( &m_cs );
|
|
return FALSE;
|
|
}
|
|
|
|
// 내용을 받을 포인터가 NULL이 아닌 경우에만 메모리를 복사한다.
|
|
if( pTar != NULL )
|
|
{
|
|
if( m_nHead < m_nTail )
|
|
{
|
|
// 1. head가 tail보다 앞에 있는 경우
|
|
memcpy( pTar, m_pData + m_nHead, sizeof(T) * nSize );
|
|
}
|
|
else
|
|
{
|
|
// 2. head가 tail보다 뒤에 있는 경우
|
|
if( GetBackDataCount() >= nSize )
|
|
{
|
|
// 뒤쪽에 남은 데이터가 꺼내갈 양보다 같거나 큰 경우 nSize만큼 한번에 복사한다.
|
|
memcpy( pTar, m_pData + m_nHead, sizeof(T) * nSize );
|
|
}
|
|
else
|
|
{
|
|
// 뒤쪽에 남은 데이터가 꺼내갈 양보다 작은 경우 두번에 나누어 복사한다.
|
|
memcpy( pTar, m_pData + m_nHead, sizeof(T) * GetBackDataCount() );
|
|
memcpy( pTar + GetBackDataCount(), m_pData, sizeof(T) * ( nSize - GetBackDataCount() ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection( &m_cs );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//=============================================================================================================================
|
|
/**
|
|
@remarks
|
|
패킷이 버퍼 뒤쪽에서 앞쪽으로 나누어질 때 패킷이 이어지도록 여분의 공간에 카피한다.
|
|
@param nSize
|
|
뒤쪽에서 잘려서 앞쪽으로 이어진 데이터의 길이
|
|
*/
|
|
//=============================================================================================================================
|
|
inline void CopyHeadDataToExtraBuffer( int nSize )
|
|
{
|
|
assert( nSize <= m_nExtraSize );
|
|
|
|
EnterCriticalSection( &m_cs );
|
|
|
|
// 버퍼 맨 뒷쪽 여분 버퍼에다가 버퍼 맨 앞쪽에 있는 데이터를 쓴다.
|
|
memcpy( m_pData + m_nSize, m_pData, nSize );
|
|
|
|
LeaveCriticalSection( &m_cs );
|
|
}
|
|
|
|
protected:
|
|
CRITICAL_SECTION m_cs;
|
|
T *m_pData; /// 큐 버퍼 포인터
|
|
int m_nLength; /// 현재 데이터 길이
|
|
int m_nSize; /// 큐 버퍼의 전체 크기
|
|
int m_nHead; /// 현재 데이터가 시작되는 곳의 위치
|
|
int m_nTail; /// 현재 데이터가 써질 곳의 위치
|
|
int m_nExtraSize; /// 큐 뒤쪽에 여분으로 잡을 버퍼 크기
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|