/*
 *	cliprc.h
 *
 *	Range Coder
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2014 Naoyuki Sawa
 *
 *	* Wed Dec 03 21:01:59 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 *	  RangeCoderDecoder_Decode(),RangeCoderDecoder_Init(),RangeCoderDecoder_Getc()のアセンブラ化も行いました。
 *	  圧縮データの作成は、DOSコマンドラインツール「tool/dprc」を利用してください。
 *	- 下記の記事を参考にしました。
 *	  「高速な算術圧縮を実現する「Range Coder」」(http://codezine.jp/article/detail/443)
 *	  (ダウンロードして「keep/高速な算術圧縮を実現する「Range Coder」.7z」に保存しておきました。)
 *	  当モジュールの実装は、サンプルソースの実装を参考にし、加えて以下の工夫を行いました。
 *	  ・圧縮時に格納する確率表が小さく済むよう工夫しました。
 *	  ・サンプルソースは確率分母がデータサイズのままですが、当モジュールは1/65536に正規化しました。
 *	  ・サンプルソースはデコーダが二分探索を行っていますが、当モジュールは出現確率が高い順に線形探索を行うようにしました。
 *	  ・サンプルソースは元データのサイズをヘッダに格納していますが、当モジュールは終端符号で判断するようにしました。
 *	- RangeCoderDecoder_Decode()の速度は、HuffmanDecoder_Decode()に較べて、おおよそ二倍遅いです。
 *	  出現確率の偏りが小さいファイルでは、圧縮率も大差無いか、又は、確率表が大きい分ハフマンよりも圧縮率が劣ります。
 *	  構造体のサイズも、ハフマンの8バイトに較べて、Range Coderは16バイトと、劣っています。
 *	  コードサイズは、ハフマンよりも、Range Coderの方が、かなり小さいです。
 *	  以上の特性を考慮すると、出現確率の偏りが大きいことが判っている場合や、コードサイズが非常に重要な場合を除いて、
 *	  一般的には、ハフマンを使用する方が適切であるように思います。
 *	* Fri Dec 05 21:45:35 JST 2014 Naoyuki Sawa
 *	- アセンブラ版RangeCoderDecoder_Getc()の、'工夫した実装'を作成しました。
 *	  RangeCoderDecoder_Decode()で、約39KB⇒約62KBの展開を行った時の速度が、約1.350秒⇒約1.272秒に高速化しました。(Clock=48MHz,Code=SRAM,Stack=FRAM)
 *	  RangeCoderDecoder_Decode()で、約39KB⇒約62KBの展開を行った時の速度が、約0.554秒⇒約0.534秒に高速化しました。(Clock=48MHz,Code=FRAM,Stack=FRAM)
 *	  詳細は、'工夫した実装'の'RangeCoderDecoder_Getc_L10〜'のループ区間のコメントを参照してください。
 *	  コードサイズは、'素直な実装'も'工夫した実装'も、同じです。
 */
#ifndef __CLIP_RC_H__
#define __CLIP_RC_H__

/****************************************************************************
 *	RangeCoderエンコーダー
 ****************************************************************************/
//全体を一度で圧縮する関数
int RangeCoderEncoder_Encode(const void* _src, int srcBytes, void* _dst, int dstBytes);

/****************************************************************************
 *	RangeCoderデコーダー
 ****************************************************************************/
//RangeCoderデコーダー構造体
typedef struct _ST_RangeCoderDecoder {		//アセンブラ版から参照しているのでレイアウト固定です。
	const unsigned char*	src;		//+ 0,4 確率表のアドレス
	const unsigned char*	srcPos;		//+ 4,4 次に読み出す符号のアドレス
	      unsigned		D;		//+ 8,4 (D:=V-L)で定義されるD
	      unsigned		R;		//+12,4 現在の区間の幅(Range)
} ST_RangeCoderDecoder;				//=16
/*--------------------------------------------------------------------------*/
//全体を一度で展開する関数
int RangeCoderDecoder_Decode(const void* src, void* _dst, int dstBytes);
//１バイトづつ展開する関数(展開ストリーム)
void RangeCoderDecoder_Init(ST_RangeCoderDecoder* pRangeCoderDecoder, const void* _src);
int RangeCoderDecoder_Getc(ST_RangeCoderDecoder* pRangeCoderDecoder);

#endif//__CLIP_RC_H__
