Files
Leviathan/Library/Internal/source/toolkit/IQueue.cpp
T
2026-06-01 12:46:52 +02:00

741 lines
13 KiB
C++

#include <cassert>
#include <cstdlib>
#include <cstring>
#include "../../include/toolkit/IQueue.h"
#include "../../include/toolkit/ILock.h"
#include "../../include/dump/XException.h"
#include "../../include/dump/XExceptionHandler.h"
class XPlainQueue : public IQueue
{
public:
XPlainQueue( IQueueAllocator * pAllocator, unsigned nLength = 8192 );
~XPlainQueue();
unsigned Write( const void* pData, unsigned nSize );
unsigned Peek( void* pBuf, unsigned nSize );
unsigned Read( void* pBuf, unsigned nSize );
bool Clear();
unsigned Size() { return m_nSize; }
unsigned FreeSize() { return m_nLength - m_nSize; }
unsigned Count() { return 1; }
const char* GetBuf() { return m_pData; }
bool Reserve( unsigned nSize ) { return increaseBuffer( nSize ); }
bool Resize( unsigned nSize )
{
if ( m_nLength < nSize ) return false;
m_nSize = nSize;
return true;
}
unsigned GetReservedSize() { return m_nLength; }
void ResetReservedSize( unsigned nSize )
{
// 사용중인 양보다 작을 수 없다.
if( Size() > nSize )
{
return;
}
m_pData = static_cast< char* >( m_pAllocator->Realloc( m_pData, nSize ) );
m_nLength = nSize;
}
private:
unsigned freeSize() { return m_nLength - m_nSize; }
bool increaseBuffer( unsigned nSize );
char* m_pData;
unsigned m_nSize;
unsigned m_nLength;
IQueueAllocator * m_pAllocator;
};
XPlainQueue::XPlainQueue( IQueueAllocator * pAllocator, unsigned nLength )
{
m_pAllocator = pAllocator;
m_pData = static_cast< char* >( m_pAllocator->Alloc( nLength ) );
if ( !m_pData )
{
XSEH::InvokeUnhandledException( 0xC000000DL );
throw XException( "XPlainQueue::Alloc() error!" );
}
m_nLength = nLength;
m_nSize = 0;
}
XPlainQueue::~XPlainQueue()
{
m_pAllocator->Free( m_pData );
}
bool XPlainQueue::increaseBuffer( unsigned nSize )
{
m_pData = static_cast< char* >( m_pAllocator->Realloc( m_pData, m_nLength + nSize ) );
m_nLength += nSize;
return true;
}
unsigned XPlainQueue::Write( const void* pData, unsigned nSize )
{
if ( !nSize ) return 0;
assert( nSize && pData );
unsigned int nFreeSize = freeSize();
if ( nFreeSize < nSize )
{
if ( !increaseBuffer( nSize - nFreeSize ) ) return 0;
}
s_memcpy( &m_pData[ m_nSize ], freeSize(), pData, nSize );
m_nSize += nSize;
return nSize;
}
unsigned XPlainQueue::Read( void *pBuf, unsigned nSize )
{
assert( nSize && Size() );
unsigned nReadSize = (std::min)( nSize, Size() );
if ( pBuf ) s_memcpy( pBuf, nSize, m_pData, nReadSize );
if ( Size() - nReadSize )
{
s_memmove( m_pData, Size(), m_pData + nReadSize, Size() - nReadSize );
}
m_nSize = Size() - nReadSize;
#ifdef _DEBUG
memset( m_pData + m_nSize, 0xcd, FreeSize() );
#endif
return nReadSize;
}
unsigned XPlainQueue::Peek( void *pBuf, unsigned nSize )
{
assert( Size() && nSize && pBuf );
unsigned nReadSize = (std::min)( nSize, Size() );
s_memcpy( pBuf, nSize, m_pData, nReadSize );
return nReadSize;
}
bool XPlainQueue::Clear()
{
m_nSize = 0;
return true;
}
class XCircularQueue : public IQueue
{
public:
XCircularQueue( IQueueAllocator * pAllocator, unsigned nLength = 8192 );
~XCircularQueue();
unsigned Write( const void* pData, unsigned nSize );
unsigned Peek( void* pBuf, unsigned nSize );
unsigned Read( void* pBuf, unsigned nSize );
unsigned Size();
unsigned FreeSize() { return freeSize(); }
unsigned Count() { return 1; }
bool Clear();
bool Reserve( unsigned nSize ) { return increaseBuffer( nSize ); }
unsigned GetReservedSize() { return m_nLength; }
bool Resize( unsigned nSize ) { return false; }
const char* GetBuf() { return 0; }
void ResetReservedSize( unsigned nSize )
{
if( Size() > nSize )
{
return;
}
char* pBuf = static_cast< char* >( m_pAllocator->Alloc( nSize ) );
if ( !pBuf ) throw XException( "XCircularQueue::ResetReservedSize::Alloc() error!" );
m_nEnd = Read( pBuf, Size() );
m_nStart = 0;
m_pAllocator->Free( m_pData );
m_pData = pBuf;
m_nLength = nSize;
}
private:
unsigned freeSize();
bool increaseBuffer( unsigned nSize );
char* m_pData;
unsigned m_nStart;
unsigned m_nEnd;
unsigned m_nLength;
IQueueAllocator * m_pAllocator;
};
inline unsigned XCircularQueue::Size()
{
if ( m_nStart == m_nEnd ) return 0;
if ( m_nStart < m_nEnd )
{
return m_nEnd - m_nStart;
}
else
{
return ( m_nLength - m_nStart ) + m_nEnd;
}
}
inline unsigned XCircularQueue::freeSize()
{
return m_nLength - Size();
}
XCircularQueue::XCircularQueue( IQueueAllocator * pAllocator, unsigned nLength )
{
m_pAllocator = pAllocator;
m_pData = static_cast< char* >( m_pAllocator->Alloc( nLength ) );
if ( !m_pData ) throw XException( "XCircularQueue::Alloc() error!" );
m_nLength = nLength;
m_nStart = m_nEnd = 0;
}
XCircularQueue::~XCircularQueue()
{
m_pAllocator->Free( m_pData );
}
unsigned XCircularQueue::Write( const void* pData, unsigned nSize )
{
assert( pData && nSize );
char* pSource = static_cast< char* >( const_cast< void* >( pData ) );
unsigned nFreeSize = freeSize();
if ( nFreeSize < nSize + 1 )
{
if ( !increaseBuffer( ( nSize - nFreeSize ) + ( m_nLength ) ) ) return 0;
}
if ( nSize + m_nEnd > m_nLength )
{
unsigned nCut = m_nLength - m_nEnd;
s_memcpy( &m_pData[ m_nEnd ], m_nLength - m_nEnd, pData, nCut );
if ( nSize - nCut > 0 ) s_memcpy( m_pData, m_nEnd, &pSource[ nCut ] , nSize - nCut );
m_nEnd = nSize - nCut;
}
else
{
s_memcpy( &m_pData[ m_nEnd ], m_nLength - m_nEnd, pData, nSize );
m_nEnd += nSize;
}
return nSize;
}
unsigned XCircularQueue::Peek( void* pBuf, unsigned nSize )
{
assert( nSize && pBuf );
unsigned nRtn = Read( pBuf, nSize );
m_nStart -= nRtn;
if ( m_nStart < 0 )
{
m_nStart = m_nStart + m_nLength;
}
return nRtn;
}
unsigned XCircularQueue::Read( void* pBuf, unsigned nSize )
{
assert( nSize );
char* pTarget = static_cast< char* >( pBuf );
unsigned nReadableSize = (std::min)( Size(), nSize );
if ( pBuf )
{
if ( m_nEnd < m_nStart )
{
if ( nReadableSize > m_nLength - m_nStart )
{
if ( m_nLength - m_nStart > 0 ) s_memcpy( pBuf, nSize, &m_pData[ m_nStart ] , m_nLength - m_nStart );
}
else
{
if ( m_nLength - m_nStart > 0 ) s_memcpy( pBuf, nSize, &m_pData[ m_nStart ] , nReadableSize );
}
if ( ( nReadableSize - ( m_nLength - m_nStart ) ) > 0 )
{
s_memcpy( &pTarget[ m_nLength - m_nStart ], nSize - (m_nLength-m_nStart), m_pData, nReadableSize - ( m_nLength - m_nStart ) );
}
}
else
{
s_memcpy( pBuf, nSize, &m_pData[ m_nStart ], nReadableSize );
}
}
m_nStart += nReadableSize;
if ( m_nStart > m_nLength )
{
m_nStart = m_nStart - m_nLength;
}
return nReadableSize;
}
bool XCircularQueue::Clear()
{
m_nStart = m_nEnd = 0;
return true;
}
bool XCircularQueue::increaseBuffer( unsigned nSize )
{
if ( nSize < m_nLength ) return false;
char* pBuf = static_cast< char* >( m_pAllocator->Alloc( m_nLength + nSize ) );
if ( !pBuf ) throw XException( "XCircularQueue::increaseBuffer::Alloc() error!" );
m_nEnd = Read( pBuf, m_nLength );
m_nStart = 0;
m_pAllocator->Free( m_pData );
m_pData = pBuf;
m_nLength += nSize;
return true;
}
class XBlockQueue : public IQueue
{
public:
XBlockQueue();
~XBlockQueue();
unsigned Write( const void* pData, unsigned nSize );
unsigned Peek( void* pBuf, unsigned nSize );
unsigned Read( void* pBuf, unsigned nSize );
unsigned Count();
bool Clear();
unsigned Size();
unsigned FreeSize() { return 1; }
bool Reserve( unsigned nSize ) { return false; }
unsigned GetReservedSize() { return 0; }
bool Resize( unsigned nSize ) { return false; }
const char* GetBuf() { return NULL; }
void ResetReservedSize( unsigned nSize ) {}
private:
void Init();
void DeInit();
struct Node
{
Node* pNext;
Node* pPrev;
char* pData;
unsigned size;
};
Node * m_pFirst;
Node * m_pLast;
unsigned m_nCount;
};
XBlockQueue::XBlockQueue()
{
Init();
}
XBlockQueue::~XBlockQueue()
{
DeInit();
}
void XBlockQueue::Init()
{
m_pFirst = NULL;
m_pLast = NULL;
m_nCount = 0;
}
void XBlockQueue::DeInit()
{
Node* p = m_pFirst;
Node* n;
while ( p )
{
n = p->pNext;
delete [] p->pData;
delete p;
p = n;
}
}
unsigned XBlockQueue::Write( const void* pData, unsigned nSize )
{
assert( nSize );
m_nCount++;
Node* p = new Node;
p->pData = new char[ nSize ];
p->size = nSize * sizeof( char );
p->pNext = NULL;
s_memcpy( p->pData, p->size, pData, nSize );
if ( m_pLast )
{
m_pLast->pNext = p;
p->pPrev = m_pLast;
m_pLast = p;
}
else
{
p->pPrev = NULL;
m_pFirst = p;
m_pLast = p;
}
return nSize;
}
unsigned XBlockQueue::Peek( void* pBuf, unsigned nSize )
{
if ( !m_pFirst ) return 0;
unsigned nReadableSize = 0;
if ( m_pFirst )
{
nReadableSize = (std::min)( m_pFirst->size, nSize );
s_memcpy( pBuf, nSize, m_pFirst->pData, nReadableSize );
}
return nReadableSize;
}
unsigned XBlockQueue::Read( void* pBuf, unsigned nSize )
{
if ( !m_pFirst ) return 0;
unsigned nReadableSize = 0;
nReadableSize = (std::min)( m_pFirst->size, nSize );
m_nCount--;
if ( pBuf != NULL )
{
s_memcpy( pBuf, nSize, m_pFirst->pData, nReadableSize );
}
Node * p;
p = m_pFirst;
m_pFirst = m_pFirst->pNext;
delete [] p->pData;
delete p;
if ( m_pFirst )
{
m_pFirst->pPrev = NULL;
}
else
{
m_pLast = NULL;
}
return nReadableSize;
}
unsigned XBlockQueue::Count()
{
return m_nCount;
}
bool XBlockQueue::Clear()
{
DeInit();
Init();
return true;
}
unsigned XBlockQueue::Size()
{
if ( !m_nCount ) return 0;
return m_pFirst->size;
}
struct XCipherQueue : public IQueue
{
XCipherQueue( IQueue * pQueue )
{
m_pQueue = pQueue;
}
~XCipherQueue()
{
delete m_pQueue;
}
unsigned Write( const void* pData, unsigned nSize )
{
// pData 를 암호화 한다
return m_pQueue->Write( pData, nSize );
}
unsigned Peek( void* pBuf, unsigned nSize )
{
return m_pQueue->Peek( pBuf, nSize );
}
unsigned Read( void* pBuf, unsigned nSize )
{
return m_pQueue->Read( pBuf, nSize );
}
unsigned Size()
{
return m_pQueue->Size();
}
unsigned FreeSize()
{
return m_pQueue->FreeSize();
}
bool Clear()
{
return m_pQueue->Clear();
}
unsigned Count()
{
return m_pQueue->Count();
}
const char* GetBuf()
{
return m_pQueue->GetBuf();
}
bool Reserve( unsigned nSize )
{
return m_pQueue->Reserve( nSize );
}
unsigned GetReservedSize()
{
return m_pQueue->GetReservedSize();
}
void ResetReservedSize( unsigned nSize )
{
m_pQueue->ResetReservedSize( nSize );
}
bool Resize( unsigned nSize )
{
return m_pQueue->Resize( nSize );
}
private:
IQueue * m_pQueue;
};
template< typename TLOCK = XCriticalSection >
struct XThreadSafeQueue : public IQueue
{
XThreadSafeQueue( IQueue * pQueue )
{
m_pQueue = pQueue;
}
~XThreadSafeQueue()
{
m_lock.Lock();
delete m_pQueue;
}
unsigned Write( const void* pData, unsigned nSize )
{
XScopedLock cs( &m_lock );
return m_pQueue->Write( pData, nSize );
}
unsigned Peek( void* pBuf, unsigned nSize )
{
XScopedLock cs( &m_lock );
return m_pQueue->Peek( pBuf, nSize );
}
unsigned Read( void* pBuf, unsigned nSize )
{
XScopedLock cs( &m_lock );
return m_pQueue->Read( pBuf, nSize );
}
unsigned Size()
{
XScopedLock cs( &m_lock );
return m_pQueue->Size();
}
unsigned FreeSize()
{
XScopedLock cs( &m_lock );
return m_pQueue->FreeSize();
}
bool Clear()
{
XScopedLock cs( &m_lock );
return m_pQueue->Clear();
}
unsigned Count()
{
XScopedLock cs( &m_lock );
return m_pQueue->Count();
}
const char* GetBuf()
{
XScopedLock cs( &m_lock );
return m_pQueue->GetBuf();
}
bool Reserve( unsigned nSize )
{
XScopedLock cs( &m_lock );
return m_pQueue->Reserve( nSize );
}
unsigned GetReservedSize()
{
XScopedLock cs( &m_lock );
return m_pQueue->GetReservedSize();
}
void ResetReservedSize( unsigned nSize )
{
XScopedLock cs( &m_lock );
m_pQueue->ResetReservedSize( nSize );
}
bool Resize( unsigned nSize )
{
XScopedLock cs( &m_lock );
return m_pQueue->Resize( nSize );
}
private:
IQueue * m_pQueue;
TLOCK m_lock;
};
IQueue * IQueue::MakeQueue( IQueueAllocator * pAllocator, unsigned nQueueSize, const char cFlag )
{
static IQueueAllocator defaultAllocator;
if ( !pAllocator ) pAllocator = &defaultAllocator;
IQueue *pQueue = NULL;
switch( cFlag & ( IQueue::CIRCULAR | IQueue::PLAIN | IQueue::BLOCK ) )
{
// 디폴트는 PLAIN Queue
default:
case IQueue::PLAIN:
pQueue = new XPlainQueue( pAllocator, nQueueSize );
break;
case IQueue::CIRCULAR:
pQueue = new XCircularQueue( pAllocator, nQueueSize );
break;
case IQueue::BLOCK:
pQueue = new XBlockQueue();
break;
}
return pQueue;
}
IQueue * IQueue::MakeQueue( unsigned nDefaultQueueSize, const char cFlag )
{
return MakeQueue( NULL, nDefaultQueueSize, cFlag );
}