/********************************************************************************
*	ファイル名：RingQueue.h														*
*	用　　　途：リングバッファを使用した高速な固定長FIFOバッファ				*
*	備　　　考：マルチスレッド対応機能有り										*
*				Windowsメッセージと同じく、ライターはバッファ満杯時はエラー、	*
*				リーダーはバッファ空時ブロッキング								*
*				リーダーは１スレッド、ライターは複数スレッド					*
*	履　　　歴：																*
********************************************************************************/
/****************************
*	 コンパイル環境設定		*
****************************/
#pragma	once

/****************************
*	インクルードファイル	*
****************************/
#include <AfxMT.h>								// スレッド用カーネルオブジェクト使用
#include "Mem.h"
#include "Atomic.h"

/****************************
*		 マクロ定数			*
****************************/

/* マルチスレッド対応アクセスモード */
#define RQ_MT_MULTI_WRITER		0x01			// 複数のライター
#define RQ_MT_BLOCKING_READER	0x02			// リーダー側ブロッキング
#define RQ_MT_FULL_ACCESS		0x03

#define RQ_SPINLOCK_LOOP		100				// 満杯/空時のスピンロックループ回数
#define	RQ_DEFAULT_DATA_QTY		100				// デフォルトの待ち行列数

/****************************
*		 構造体定義			*
****************************/

/****************************
*		 クラス宣言			*
****************************/
class CRingQueue ;

/****************************
*		 クラス定義			*
****************************/

class CRingQueue
{
public:
		/***** コンストラクタ ****************************************************/
			// デフォルトコンストラクタ
								 CRingQueue() ;
			// サイズ初期化コンストラクタ
								 CRingQueue( UINT32 nDataSize, 
											 UINT32 nQuantity=RQ_DEFAULT_DATA_QTY, 
											 UINT32 nMTMode=0                     ) ;
			 // デストラクタ
	virtual						~CRingQueue() ;

		/***** イニシャライズ・リセット ******************************************/
			// データサイズの設定
	virtual	BOOL				SetDataSize( UINT32 nDataSize, 
											 UINT32 nQuantity=RQ_DEFAULT_DATA_QTY, 
											 UINT32 nMTMode=0                     ) ;
			// データサイズの取得
	virtual UINT32				GetDataSize() const ;
	virtual UINT32				GetQuantity() const ;

			// マルチスレッドモード設定
	virtual BOOL				SetMTMode( UINT32 nMTMode ) ;
			
			// バッファ内の全データ削除・解放
	virtual BOOL				RemoveAll() ;
			// キューのリセット（バッファは解放されない）
	virtual BOOL				Reset() ;

			// 送受信停止
	virtual BOOL				ShutDown() ;
	virtual BOOL				IsShutDown() ;

		/***** キューアクセサ *****************************************************/
			// キューへのデータ追加
	virtual	BOOL				Push( void* pvSrc, UINT32 nSize=0 ) ;
			// キューよりデータ取得
	virtual	INT32				Pop ( void* pvDst, UINT32 nTimeout=INFINITE ) ;
			// キューの先頭データの参照
	virtual INT32				Peek( void* pvDst=0 ) ;
			// キューの先頭から任意位置のデータの参照
	virtual INT32				Peek( INT32 nPeekIndexNum, void* pvDst=0 ) ;

protected:
	template<typename T>
			BOOL				PushT( T& rSrc ) ;
	template<typename T>
			INT32				PopT ( T* pDst, UINT32 nTimeout=INFINITE ) ;
	template<typename T>
			INT32				PeekT( T* pDst=0 ) ;
	template<typename T>
			INT32				PeekT( INT32 nPeekIndexNum, T* pvDst=0 ) ;

private:
		/***** 内部メソッド *******************************************************/
			void				InitMember( UINT32 nDataSize, 
											UINT32 nQuantity ) ;
			INT32				RingIncrement( INT32* nIndex ) ;
			INT32				RingDecrement( INT32* nIndex ) ;						// 1つ前
			INT32				RingDecrement( INT32 nDecrement, INT32* nIndex ) ;		// 任意数前

protected:
		/***** 内部型       *******************************************************/
	struct Packet
	{
			INT64				iSize ;					// 8byteアライメントに合わせるため
														// 64bit整数としている
			BYTE				aData[1] ;				// 以降に実際のデータが入る
	} ;

protected:
		/***** メンバー ***********************************************************/
			UINT32				m_nDataSize ;			// キュー内のデータサイズ
			UINT32				m_nPacketSize ;			// キュー内のパケットサイズ
			UINT32				m_nQuantity ;			// キュー内の要素数
	
			INT32				m_nWriteIndex ;			// ライターインデックス(Push)
			INT32				m_nReadIndex ;			// リーダーインデックス(Pop)
			ATOMIC_PTR*			m_ppvQueue ;			// キュー本体
			BYTE*				m_pbyPackets ;			// パケットバッファ
			ATOMIC_LONG			m_lbShutDown ;			// 送受信停止フラグ

			CCriticalSection*	m_plkWrite ;			// ライター排他制御
			HANDLE				m_hsmRead ;				// リーダーブロッキング用セマフォ
			
			CMemBuffer			m_MemQueue ;			// キュー用メモリ
			CMemBuffer			m_MemPackets ;			// キュー内パケットバッファ用メモリ
} ;

/****************************/
/*        テンプレート      */
/****************************/
template<typename T>
class TRingQueue
	: protected CRingQueue 
{
public:
			// デフォルトコンストラクタ
								TRingQueue() ;
			// サイズ初期化コンストラクタ
								TRingQueue( UINT32 nQuantity, 
											UINT32 nMTMode=0 ) ;
			 // デストラクタ
	virtual					   ~TRingQueue() ;

		/***** イニシャライズ・リセット ******************************************/
			// データサイズ設定
			BOOL				SetDataSize( UINT32 nQuantity=RQ_DEFAULT_DATA_QTY, 
											 UINT32 nMTMode=0                     ) ;
			// データ数の取得
	virtual UINT32				GetQuantity() const ;

			// マルチスレッドモード設定
	virtual BOOL				SetMTMode( UINT32 nMTMode ) ;
			
			// バッファ内の全データ削除・解放
	virtual BOOL				RemoveAll() ;

			// キューのリセット（バッファは解放されない）
	virtual BOOL				Reset() ;

			// 送受信停止
	virtual BOOL				ShutDown() ;
	virtual BOOL				IsShutDown() ;

		/***** キューアクセサ *****************************************************/
			// キューへのデータ追加
			BOOL				Push( T& rSrc ) ;

			// キューよりデータ取得
			INT32				Pop ( T* pDst, UINT32 nTimeout=INFINITE ) ;

			// キューの先頭データの参照
			INT32				Peek( T* pvDst=0 ) ;

			// キューの先頭から任意位置のデータの参照
			INT32				Peek( INT32 nPeekIndexNum, T* pvDst=0 ) ;
} ;

// テンプレート定義
#include "RingQueue.hpp"

/****************************
*		 関数　定義			*
****************************/
/****************************
*		 変数　定義			*
****************************/
