/*	
 *	clipmemc.h
 *
 *	コンパクション機能付きメモリブロック管理
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015-2016 Naoyuki Sawa
 *
 *	* Sat Dec 26 13:49:23 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	- 当モジュールの目的は、以下の通りです。
 *	  1. 標準ライブラリの動的メモリ関数(malloc(),free()等)が使えない、小規模な組み込み環境等に、単純な動的メモリ関数を提供する事。
 *	  2. コンパクション機能を提供する事。メモリ容量が少ない環境では、フラグメンテーションで連続領域が確保出来なくなり易いからです。
 *	- 当モジュールの主な制限事項は、以下の通りです。
 *	  1. 同時に割り当てられるブロック数の上限は、65535個です。
 *	  2. 同時に割りあてられるブロックの合計サイズの上限は、(4*65535)=256キロバイト弱です。
 *	  小規模な組み込み環境で使う分には、充分だと思います。
 *	- コンパクションの注意点について説明します。
 *	  当モジュールは、MemCpt_Free()が呼び出された時に、自動的にコンパクションを実行します。
 *	  そうする事によって、バッファ領域の途中に空き領域が発生せず、フラグメンテーションが発生しません。
 *	  コンパクションが実行されると(=MemCpt_Free()が呼び出されると)、ブロックのアドレスが移動する可能性が有ります。
 *	  アプリケーションは、MemCpt_Free()の呼び出しをまたいで、ブロックのアドレスを保持してはいけません。
 *	  実際には、MemCpt_Free()の呼び出しの有無に関係なく、常に、ブロックの領域にアクセスする直前に、毎回、MemCpt_Ptr()を呼び出してポインタを取得するのが望ましいです。
 *	- コンパクションは、多少コストの高い処理ですが、とはいえ、極端に遅い訳ではありません。
 *	  メモリブロック全体を一回走査する事と、メモリ領域を一回移動するだけだからです。
 *	  アプリケーションが、MemCpt_Free()の呼び出しを避ける事に神経質になる必要は有りません。
 *	* Mon Jun 06 21:45:00 JST 2016 Naoyuki Sawa
 *	- MemCpt_Resize()を追加しました。
 *	* Tue Jun 07 22:13:11 JST 2016 Naoyuki Sawa
 *	- 「MemCpt_Resize()のテストスイート」を追記しました。
 *	  プログラムには変更有りません。
 */
#ifndef __CLIP_MEMC_H__
#define __CLIP_MEMC_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
#ifndef __RENESAS__
#define USE_MEMCPT_DUMP	//MemCpt_Dump()が不要ならばこのシンボル定義をコメントアウトしてください。
#endif//__RENESAS__
/****************************************************************************
 *	構造体、マクロ
 ****************************************************************************/
//メモリブロック
typedef struct _ST_MemCptBk {
	uint16_t	iAddr;			//+0,2			先頭アドレス		0〜nWords			空きブロックの判定は(iSize==0)で行いますが、処理の効率化のために、空きブロックはiAddrも0としています。詳細はMemCpt_Free()の実装を参照して下さい。
	uint16_t	iSize;			//+2,2			ブロックのワード数	1〜nWords,又は,0(空ブロック)
} ST_MemCptBk;					//=4
/*--------------------------------------------------------------------------*/
//コンパクション機能付きメモリブロック管理
typedef struct _ST_MemCpt {
	uint16_t	nBlock;			//+0,2			ブロック配列の要素数	0〜UINT16_MAX
	uint16_t	nWords;			//+2,2			バッファの要素数	0〜UINT16_MAX
	uint16_t	iFree;			//+4,2			空き領域の先頭アドレス	0〜(nWords-1),又は,nWords(空き領域無し)
	uint16_t	padding;		//+6,2			(パディング)
    //	ST_MemCptBk	TBL_Block[nBlock];	//+8,4*nBlock		ブロック配列
    //	uint32_t	TBL_Words[nWords];	//+8+4*nBlock,4*nWords	バッファ
} ST_MemCpt;					//=8+4*nBlock+4*nWords
/*--------------------------------------------------------------------------*/
//管理構造体のメモリを静的に確保するマクロ
#define MemCpt_Def(name,nBlock,nBytes) ST_MemCpt name[1+(((nBlock)+(((nBytes)+3)>>2)+1)>>1)]
//                                                        ~~~~~~~~ ~~~~~~~~~~~~~~~~~        ← 4バイト単位
//                                                    ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ← 8バイト単位
/****************************************************************************
 *	グローバル関数宣言
 ****************************************************************************/
ST_MemCpt* MemCpt_New(int nBlock, int nBytes/*4N*/);	//開放はfree()を使って下さい。
void MemCpt_Init(ST_MemCpt* pMemCpt, int nBlock, int nBytes/*4N*/);
int MemCpt_Alloc(ST_MemCpt* pMemCpt, int iAllocBytes);
int MemCpt_Resize(ST_MemCpt* pMemCpt, int iBlock/*0,1〜nBlock*/, int iNewBytes);
void MemCpt_Free(ST_MemCpt* pMemCpt, int iBlock/*0,1〜nBlock*/);
void* MemCpt_Ptr(ST_MemCpt* pMemCpt, int iBlock/*0,1〜nBlock*/);
#ifdef  USE_MEMCPT_DUMP
void MemCpt_Dump(FILE* fp, ST_MemCpt* pMemCpt);
#endif//USE_MEMCPT_DUMP
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif//__CLIP_MEMC_H__
