www.pudn.com > using IOCP.zip > buffer.h


 
// Written by Oz Ben Eliezer 
// o_be@hotmail.com 
// September, 2000 
 
#ifndef __BUFFER_H__		// Sentinels 
#define __BUFFER_H__ 
 
#include  
#include  
 
#include "general.h" 
 
extern int BASE_BUFFER_SIZE; 
extern int BASE_BUFFER_INC; 
 
class CAutoBuffer 
{ 
protected: 
	char *buffer;							// Yeah, this is our buffer 
	int nLength;							// Current length of data 
	int nSize;								// Current size of buffer 
	int nIncrement;							// By how much we should increment 
											// when buffer is too small 
	CRITICAL_SECTION csInUse;				// Make it thread safe 
 
	/*	 
		__forceinline is a Microsoft-specific keyword, which forces the 
		compiler into inlining the code. In practice, the compiler can still 
		deny in inlining, but it will produce a warning. In order to create 
		a non-thread-safe version of this class, just inherit from it, and 
		override the XXXInUse functions, to do nothing. 
	*/ 
 
	__forceinline void EnterInUse() 
	{ 
		EnterCriticalSection(&csInUse); 
	} 
 
	__forceinline void LeaveInUse() 
	{ 
		LeaveCriticalSection(&csInUse); 
	} 
 
	__forceinline void InitializeInUse() 
	{ 
		InitializeCriticalSection(&csInUse); 
	} 
 
	__forceinline void DeleteInUse() 
	{ 
		DeleteCriticalSection(&csInUse); 
	} 
 
	/* 
		The IncreaseSize(..) function re-allocates memory space for the 
		buffer and copies its current contents into the new memory space. 
	*/ 
	__forceinline void IncreaseSize(int nIncrement_) 
	{ 
		char *newbuf; 
 
		EnterInUse(); 
 
		newbuf = new char [nSize + nIncrement_]; 
		memcpy(newbuf, buffer, nSize); 
 
		delete [] buffer; 
		buffer = newbuf; 
		nSize += nIncrement_; 
 
		LeaveInUse(); 
	} 
 
	__forceinline void IncreaseSize() 
	{ 
		IncreaseSize(nIncrement); 
	} 
 
public: 
	CAutoBuffer(int nIncrement_) : buffer(NULL), 
		nLength(0), 
		nIncrement(nIncrement_) 
	{ 
		InitializeInUse(); 
		buffer = new char [BASE_BUFFER_SIZE];	// Allocate memory 
		nSize = BASE_BUFFER_SIZE; 
	} 
 
	~CAutoBuffer() 
	{ 
		DeleteInUse(); 
		if (buffer) 
			delete [] buffer;					// De-allocate memory 
	} 
 
	/* 
		I assume that memory can be allocated, and that the new keyword 
		never returns NULL. I didn't embed error-detection in order to 
		enhance performance. If there is not enough memory to be allocated, 
		something is terribly wrong. 
 
		Furthermore, no internal memory checks are performed inside the 
		functions. 
	*/ 
 
	/* 
		AddToBuffer(..) adds data from a source buffer to the class' buffer. 
		src: the source buffer 
		len: the source buffer's size 
	*/ 
	__forceinline void AddToBuffer(const char *src, int len) 
	{ 
		if (len > 0) 
		{ 
			if (len + nLength > nSize) 
				IncreaseSize(BASE_BUFFER_INC > len ? BASE_BUFFER_INC : len); 
 
			EnterInUse(); 
 
			memcpy(buffer + nLength, src, len); 
			nLength += len; 
 
			LeaveInUse(); 
		} 
	} 
 
	/* 
		AddToBufferBeg(..) adds data from a source buffer to the beginning 
		of the class' buffer. 
	*/ 
	__forceinline void AddToBufferBeg(const char *src, int len) 
	{ 
		if (len + nLength > nSize) 
			IncreaseSize(len); 
 
		EnterInUse(); 
 
		memmove(buffer + len, buffer, nLength); 
		memcpy(buffer, src, len); 
		nLength += len; 
 
		LeaveInUse(); 
	} 
 
	/* 
		GetBuffer(..) copies data from the class' buffer to a destination 
		buffer. dst is a pointer to the destination buffer. len is a pointer 
		to an integer that specifies the size of dst. The value to which len 
		points is changes by the function, to reflect the number of bytes 
		transferred from the class' buffer to the destination buffer. 
	*/ 
	__forceinline void GetBuffer(char *dst, int *len) 
	{ 
		if (nLength > *len) 
		{	// Supplied buffer is not large enough. 
			GetFromBuffer(dst, len); 
		} 
		else 
		{ 
			EnterInUse(); 
 
			memcpy(dst, buffer, nLength); 
			*len = nLength; 
			nLength = 0;		// Clear buffer; 
 
			LeaveInUse(); 
		} 
	} 
 
	__forceinline void GetFromBuffer(char *dst, int *len) 
	{ 
		if (*len > nLength) 
		{ 
			GetBuffer(dst, len); 
			return; 
		} 
		else if (*len != 0) 
		{ 
			EnterInUse(); 
 
			memcpy(dst, buffer, *len); 
			memmove(buffer, buffer + *len, nLength - *len); 
			nLength -= *len; 
 
			LeaveInUse(); 
		} 
	} 
 
	__forceinline char *GetBuffer() 
	{ 
		return buffer; 
	} 
 
	__forceinline bool IsEmpty() 
	{ 
		return (nLength == 0); 
	} 
 
	__forceinline bool GetPacket(tagPacket *p) 
	{ 
		bool bRet = false;	// Assume that no packet is available. 
 
		EnterInUse(); 
 
		if (nLength >= 4)	// Received size description 
		{ 
			memcpy(p, buffer, 4);		// Size 
 
			// See if enough data has arrived 
			if ((unsigned)p->nLength <= (unsigned int)(nLength - 4)) 
			{ 
				// Packet is available. Copy data into packet. 
				// Allocate memory for packet's buffer. 
				p->buffer = new char [p->nLength]; 
 
				memcpy(p->buffer, buffer + 4, p->nLength); 
				memmove(buffer, buffer + 4 + p->nLength, nLength - p->nLength - 4); 
				///////////////// FIXED - memmove moves nLength - p->nLength - 4 bytes, instead of 
				/////////////////			nLength - p->nLength 
 
				nLength -= p->nLength; 
				nLength -= 4; 
 
				bRet = true; 
			} 
		} 
 
		LeaveInUse(); 
 
		return bRet; 
	} 
}; 
 
#endif