/*
 *	clipbpe.c
 *
 *	Byte Pair Encoding
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015 Naoyuki Sawa
 *
 *	* Thu Jan 29 21:20:19 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	- 下記の資料を参考にさせて頂きました。
 *	  「Vector - bpe - BPE圧縮/展開するコマンドラインツール」(http://www.vector.co.jp/soft/dl/winnt/util/se498916.html)
 *	  「ひそかにぐあんをめぐらして - Byte Pair Encoding・その１」(http://musyozoku211.blog118.fc2.com/blog-entry-8.html)
 *	* Fri Jan 30 21:08:25 JST 2015 Naoyuki Sawa
 *	- 「１バイトづつ展開する関数(展開ストリーム)」を高速化するために、大幅な変更を行いました。
 *	  データの特性に関係無く、「１バイトづつ展開する関数(展開ストリーム)」が常に安定した速度で動作するようになりました。
 *	  今回の変更によって、僅かに圧縮率が低下しましたが、ほとんど無視できるレベルだと思います。
 *	* Mon Feb 02 00:23:19 JST 2015 Naoyuki Sawa
 *	- BytePairEncodingEncoder_Encode()をマルチスレッドに対応しました。
 *	  Visual C++ 6.0の「プロジェクトの設定」の「ランタイムライブラリ」に「マルチスレッド」を選択すると、マルチスレッド版を使用します。
 *	  Visual C++ 6.0の「プロジェクトの設定」の「ランタイムライブラリ」に「シングルスレッド」を選択すると、これまでと同じ通常版を使用します。
 *	* Mon Feb 02 21:59:02 JST 2015 Naoyuki Sawa
 *	- マルチスレッド版のBytePairEncodingEncoder_Encode()が(srcLen=1)の場合に終了しなかったバグを修正しました。
 */
#include "clip.h"

/****************************************************************************
 *	BytePairEncodingエンコーダー
 ****************************************************************************/
#ifdef  WIN32
#define BYTEPAIRENCODINGENCODER_PRINTPROGRESS //このシンボルを定義するとBytePairEncodingEncoder_Encode()が標準エラー出力に進捗表示を表示する。この行をコメントアウトすれば表示しない。
#endif//WIN32
typedef struct _ST_BytePairEncodingEncoder {
	int		valueCount[65536];	//文字,又は,ペアの出現回数。文字の出現回数を数える時は[0]〜[255]だけを使用する。
	unsigned char	charToCode[256];	//文字から符号への変換表。
	unsigned short	codeValue[256];		//符号から文字への変換表。符号[0]は使用しない。[1]〜[nChar]は文字(下位8bitのみ使用)。[nChar+1]〜[nCode]はペア(下位8bit,上位8bitの順)。
	unsigned char	codeDepth[256];		//符号の深さ。符号の深さとはこの符号を展開する時のスタック消費量です。文字の符号ならば0。ペア(x,y)の符号ならばmax(xの深さ,yの深さ)+1。		ペアに割り当てられる符号の数は最大で(254-1)なので符号の深さの最大値は254であり(unsigned char)で足りる。
	unsigned char	src[0/*srcLen以上*/];	//圧縮元データのコピーを作成するためのバッファ。
} ST_BytePairEncodingEncoder;
/*--------------------------------------------------------------------------*/
//BytePairEncodingEncoder_Encode()から呼び出すローカル関数
static int BytePairEncodingEncoder_EncodeSub(ST_BytePairEncodingEncoder* pEncoder, const void* _src, int srcLen, void* _dst, int dstCap) {
	unsigned char* src = memcpy(pEncoder->src, _src, srcLen);	//圧縮元データのコピーを作成する。
	unsigned char* dst = _dst;
	int dstLen = -1;	//'圧縮不可'と判断した場合は-1を返すために、圧縮後データ長を-1としておく。
	int c, lo, hi, iSrc, nChar, nCode;
	//文字の出現回数を数える。
	memset(pEncoder->valueCount, 0, sizeof pEncoder->valueCount);	//出現回数をクリアする。
	for(iSrc = 0; iSrc < srcLen; iSrc++) {
		c = src[iSrc];
		pEncoder->valueCount[c]++;
	}
	//文字に符号を割り当てる。
	nCode = 1;	//割り当てた符号の数。符号[0]は使用しない。[1]から開始する。
	for(c = 0; c < 256; c++) {
		if(pEncoder->valueCount[c]) {
			if(nCode >= 256) { return -1; }		//文字に符号が割り当てられなければ'圧縮不可'と判断する。全ての文字が出現した場合にこうなる。	'圧縮不可'と判断した場合は-1を返す。
			pEncoder->charToCode[c] = nCode;	//文字から符号への変換表を格納する。
			pEncoder->codeValue[nCode] = c;		//符号から文字への変換表を格納する。
			nCode++;				//割り当てた符号の数を増やす。
		}
	}
	nChar = nCode;	//符号[0],及び,文字に割り当てた符号の数を保存する。
	//文字を符号に置き換える。
	for(iSrc = 0; iSrc < srcLen; iSrc++) {
		c = src[iSrc];
		c = pEncoder->charToCode[c];
		src[iSrc] = c;
	}
	//--- 二回以上出現するペアを、一個の符号に置き換える処理 ---
	memset(pEncoder->codeDepth, 0, sizeof pEncoder->codeDepth);	//符号の深さをクリアする。
	while(nCode < 256) {	//ペアに割り当てる符号が残っていれば…
		int cPrev, maxPair, maxCount;
		//ペアの出現回数を数える。
		memset(pEncoder->valueCount, 0, sizeof pEncoder->valueCount);	//出現回数をクリアする。
		cPrev = -1;						//←┐
		for(iSrc = 0; iSrc < srcLen - 1; iSrc++) {		//　│'AAA' の場合、前半の'AA_' は数える。後半の'_AA' は数えない。
			c = src[iSrc] | (src[iSrc+1]<<8);		//　│'AAAA'の場合、前半の'AA__'は数える。中央の'_AA_'は数えない。後半の'__AA'は数える。
			cPrev = (cPrev != c) ? c : -1;			//←┤理由は、'数える'部分をペア化した後では、'数えない'部分はペア化できないからである。
			if(c != -1) { pEncoder->valueCount[c]++; }	//←┘
		}
		//出現回数が最大であるペアを取得する。
		maxPair = maxCount = 0;
		for(c = 0; c < 65536; c++) {
			lo = (unsigned char)(c>>0);	//下位8bitの符号
			hi = (unsigned char)(c>>8);	//上位8bitの符号
			lo = pEncoder->codeDepth[lo];	//下位8bitの符号の深さ
			hi = pEncoder->codeDepth[hi];	//上位8bitの符号の深さ
			if(max(lo,hi) < FIELD_SIZEOF(ST_BytePairEncodingDecoder,stk)) {	//両方の符号の深さが上限未満ならばペア化可能です。
				if(pEncoder->valueCount[c] > maxCount) {
					maxPair  = c;
					maxCount = pEncoder->valueCount[c];
				}
			}
		}
		//二回以上出現するペアが無ければ、圧縮処理はここまでとする。
		if(maxCount < 2) { break; }
		//ペアを符号に置き換える。
		for(iSrc = 0, dstLen = 0; iSrc < srcLen; iSrc++, dstLen++) {
			c = src[iSrc];
			if(iSrc < srcLen - 1) { c |= (src[iSrc+1]<<8); }	//ここを通らなければ上位8bit=0となり、偶然maxPairに一致する心配は無い。符号[0]は使用しないので、ペアの上位8bit=0である事は無いからです。
			if(c == maxPair) { c = nCode; iSrc++; }
			src[dstLen] = c;
		}
		srcLen = dstLen;
		//ペアに符号を割り当てる。
		pEncoder->codeValue[nCode] = maxPair;		//符号からペアへの変換表を格納する。
		lo = (unsigned char)(maxPair>>0);		//下位8bitの符号
		hi = (unsigned char)(maxPair>>8);		//上位8bitの符号
		lo = pEncoder->codeDepth[lo];			//下位8bitの符号の深さ
		hi = pEncoder->codeDepth[hi];			//上位8bitの符号の深さ
		pEncoder->codeDepth[nCode] = max(lo,hi) + 1;	//符号の深さを格納する。
		nCode++;					//割り当てた符号の数を増やす。
	}
	//--- 圧縮後データを出力する処理 ---
	dstLen = 0;
	//出力バッファが指定されていたら…
	if(dstCap) {	//この条件判断を行わなくても動作上は問題無い。高速化のためだけです。
		//変換表を出力する。
		if(dstLen < dstCap) { *dst++ = (nChar -     1); } dstLen++;	//文字に割り当てた符号の数を出力する。
		if(dstLen < dstCap) { *dst++ = (nCode - nChar); } dstLen++;	//ペアに割り当てた符号の数を出力する。
		for(c = 1; c < nCode; c++) {					//符号[0]以外の全ての符号について…
			if(c < nChar) {	//文字に割り当てられた符号ならば…
				if(dstLen < dstCap) { *dst++ = (unsigned char) pEncoder->codeValue[c]    ; } dstLen++;	//文字を出力する。
			} else {	//ペアに割り当てられた符号ならば…
				if(dstLen < dstCap) { *dst++ = (unsigned char)(pEncoder->codeValue[c]>>8); } dstLen++;	//ペアの後続符号を出力する。	//┬デコーダを最適化するためにペアの変換表は{後続符号,先行符号}の順とする。
				if(dstLen < dstCap) { *dst++ = (unsigned char)(pEncoder->codeValue[c]>>0); } dstLen++;	//ペアの先行符号を出力する。	//┘frambpe.cのBytePairEncodingDecoder_Getc()の実装を参照せよ。
			}
		}
		//符号を出力する。
		for(iSrc = 0; iSrc < srcLen; iSrc++) {
			if(dstLen < dstCap) { *dst++ = src[iSrc]; } dstLen++;
		}
		//終端符号(符号[0])を出力する。
		if(dstLen < dstCap) { *dst++ = 0; } dstLen++;
	//出力バッファが指定されていなければ…
	} else {
		dstLen = 1			//文字に割り当てた符号の数
		       + 1			//ペアに割り当てた符号の数
		       + (nCode -     1)	//文字,又は,ペアの下位8bit
		       + (nCode - nChar)	//          ペアの上位8bit
		       + srcLen			//符号
		       + 1;			//終端符号(符号[0])
	}
	//圧縮後データ長が65536バイトを超過した場合は'圧縮不可'と判断し-1を返す。
	// - 圧縮後データ長が65536バイトを超過不可とする理由は、ST_BytePairEncodingDecoder.ofsで65536を表現出来ないからです。
	// - 厳密にはぴったり65536の場合もST_BytePairEncodingDecoder.ofsで表現出来ませんが、ぴったり65536の場合は可とします。
	//   なぜなら終端符号(符号[0])を読み出した直後のofs値を、ST_BytePairEncodingDecoder.ofsに格納することは無いからです。
	//   具体的には、BytePairEncodingDecoder_Getc()の実装を参照してください。
	if(dstLen > 65536) { return -1; }
	//圧縮後データ長を返す。
	return dstLen;
}
/*--------------------------------------------------------------------------*/
//全体を一度で圧縮する関数
#if     defined(_WIN32) && defined(_MT)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//マルチスレッド版	｢ﾌﾟﾛｼﾞｪｸﾄの設定｣⇒｢C/C++｣⇒｢ｺｰﾄﾞ生成｣⇒｢使用するﾗﾝﾀｲﾑﾗｲﾌﾞﾗﾘ｣⇒｢ﾏﾙﾁｽﾚｯﾄﾞ｣/｢ﾏﾙﾁｽﾚｯﾄﾞ(ﾃﾞﾊﾞｯｸﾞ)｣を選択した時はこちらを使用します｡
typedef struct _ST_BytePairEncodingEncoderMT {
	const unsigned char*	src/*[srcLen]*/;
	int			srcLen;
	int			divLev;				//次に実行する分割レベル-1	InterlockedIncrement()を使ってアクセスし分割数divCnt=(1<<戻り値)を実行する。初回の戻り値を0とするために-1に初期化せよ。
	int			dstLen[32/*divLev*/];		//0=未完了,-1=圧縮不可,>0=圧縮後データ長
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
	int			  iBlk[32/*divLev*/];
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
	HANDLE			hEvent;				//サブスレッドが当構造体を何か変更した事を、メインスレッドへ通知するためのイベント
	int			reqExit;			//メインスレッドから、サブスレッドへの終了要求フラグ	サブスレッド取得した分割数が圧縮元データ長を超過した場合も終了します。
	int			numThread;			//終了していないサブスレッドの数	インクリメントもサブスレッド側で行う。安全である理由はBytePairEncodingEncoder_Encode()の「サブスレッドの次の処理を待つ」部分のコメントを参照せよ。
} ST_BytePairEncodingEncoderMT;
static void BytePairEncodingEncoder_EncodeTry(volatile ST_BytePairEncodingEncoderMT* pMT) {
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
	InterlockedIncrement((int*)&pMT->numThread);
	{
		const unsigned char* src    = pMT->src;
		int                  srcLen = pMT->srcLen;
		int iBlk, divLev, divCnt, dstLen, blkPos, blkLen, tmpLen;
		//ワークメモリを確保する。
		ST_BytePairEncodingEncoder* pEncoder = malloc(sizeof(ST_BytePairEncodingEncoder) + srcLen);
		if(!pEncoder) { DIE(); }
		for(;;) {
			divLev = InterlockedIncrement((int*)&pMT->divLev);	//次に実行する分割レベルを取得する。
			divCnt = (1 << divLev);
			if(divCnt > srcLen) { break; }				//サブスレッド取得した分割数が圧縮元データ長を超過した場合も終了します。
			dstLen = 0;
			for(iBlk = 0; iBlk < divCnt; iBlk++) {
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
				pMT->iBlk[divLev] = iBlk;
				SetEvent(pMT->hEvent);
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
				//このブロックの圧縮後データ長を求め、加算する。
				blkPos = (int)((int64_t)srcLen * (int64_t)(iBlk + 0) / (int64_t)divCnt);		//┬この二行の計算はint64_t型へのキャスト必須です。もしint型のまま計算すると、
				blkLen = (int)((int64_t)srcLen * (int64_t)(iBlk + 1) / (int64_t)divCnt) - blkPos;	//┘数MB以上のファイルを圧縮しようとした時にオーバーフローして異常終了します。
				tmpLen = BytePairEncodingEncoder_EncodeSub(pEncoder, &src[blkPos], blkLen, NULL, 0);
				if(tmpLen < 0) { dstLen = -1; break; }
				dstLen += tmpLen;
				if(pMT->reqExit) { goto L_EXIT; }
			}
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
			pMT->iBlk[  divLev] = iBlk;
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
			pMT->dstLen[divLev] = dstLen;
			SetEvent(pMT->hEvent);
		}
L_EXIT:		//ワークメモリを開放する。
		free(pEncoder);
	}
	InterlockedDecrement((int*)&pMT->numThread);
	SetEvent(pMT->hEvent);
}
int BytePairEncodingEncoder_Encode(const void* _src, int srcLen, void* _dst, int dstCap) {
	const unsigned char* src = _src;
	      unsigned char* dst = _dst;
	int dstLen = 0;	//(srcLen=0)だった場合のために(dstLen=0)としておく。
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
	int newMsgLen, oldMsgLen = 0;
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
	//圧縮元データが空でなければ…
	if(srcLen) {
		int iBlk, divCnt, blkPos, blkLen, tmpLen;
		//ワークメモリを確保する。
		ST_BytePairEncodingEncoder* pEncoder = malloc(sizeof(ST_BytePairEncodingEncoder) + srcLen);
		if(!pEncoder) { DIE(); }
		//--- 最適な分割数を求める処理 ---
		{
			volatile ST_BytePairEncodingEncoderMT stMT;
			SYSTEM_INFO si;
			int i, divLev;
			memset((void*)&stMT, 0, sizeof stMT);
			stMT.src    = src;
			stMT.srcLen = srcLen;
			stMT.divLev = -1;			//次に実行する分割レベル-1	InterlockedIncrement()を使ってアクセスし分割数divCnt=(1<<戻り値)を実行する。初回の戻り値を0とするために-1に初期化せよ。
			stMT.hEvent = CreateEvent(NULL, FALSE/*自動リセットオブジェクト*/, FALSE/*非シグナル状態*/, NULL);
		//{{2015/02/02追加:マルチスレッド版のBytePairEncodingEncoder_Encode()が(srcLen=1)の場合に終了しなかったバグを修正しました。
		// * Mon Feb 02 21:59:02 JST 2015 Naoyuki Sawa
		// - マルチスレッド版のBytePairEncodingEncoder_Encode()が(srcLen=1)の場合に終了しなかったバグを修正しました。
		// - 上記のバグが発生していた理由は以下の通りです。
		//   マルチスレッド版のBytePairEncodingEncoder_Encode()の「最適な分割数を求める処理」の終了条件は、「隣り合う分割レベルが圧縮可能で増加傾向に転じている箇所を見つけた時」です。
		//   しかし(srcLen=1)の場合は、BytePairEncodingEncoder_EncodeTry()が圧縮レベル0しか探索しないので、上記の条件を満たさず、BytePairEncodingEncoder_Encode()がいつまでも待ち続けてしまうからです。
		// - 上記のバグを修正するために、(srcLen=1)の場合のみ、明示的に分割レベル0を選択する特例処理を追加しました。
		// - (srcLen=0)の場合は上で除外されているので、ここで考慮する必要は有りません。
		//   (srcLen=2)の場合は分割レベル0と1が探索されるので、普段どおりの終了条件を満たして終了するので、ここで考慮する必要は有りません。
		// - 尚、ここで述べた対策はマルチスレッド版でのみ必要な対策であり、通常版では(srcLen=1)には特例処理は必要でありません。
		//   なぜなら、通常版の探索打ち切り条件は「隣り合う分割レベルが圧縮可能で増加傾向に転じている箇所を見つけた時」ではなく、
		//   「圧縮可能な分割数を順に試して行って増加傾向に転じたとき」であるので、(srcLen=1)の場合も普段どおりの処理で問題無いからです。
			if(srcLen == 1) { divLev = 0; goto L_EXIT; }
		//}}2015/02/02追加:マルチスレッド版のBytePairEncodingEncoder_Encode()が(srcLen=1)の場合に終了しなかったバグを修正しました。
			GetSystemInfo(&si);
			for(i = 0; (int)i < (int)si.dwNumberOfProcessors; i++) {			//論理プロセッサの数だけ…
				_beginthread(BytePairEncodingEncoder_EncodeTry, 0, (void*)&stMT);	//サブスレッドを作成する。
			}
			for(;;) {
				WaitForSingleObject(stMT.hEvent, INFINITE);	//サブスレッドの次の処理を待つ。	少なくとも一回はここで待つので、stMT.numThreadの初期インクリメントをサブスレッド側で行って安全です。
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
				divLev = stMT.divLev;
				if((unsigned)divLev < 32) {	//(divLev<0),又は,(divLev>31)になる可能性も有るので除外する事を忘れないように。
					divCnt = (1 << divLev);
					iBlk = stMT.iBlk[divLev];
					newMsgLen = fprintf(stderr, "\rtry srcLen=%d divCnt=%d (%d/%d)", srcLen, divCnt, iBlk, divCnt);
					if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } oldMsgLen = newMsgLen;
				}
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
				for(divLev = 0; divLev < (32 - 1); divLev++) {		//隣り合う分割レベルについて…
					int dstLen0 = stMT.dstLen[divLev + 0];		//(分割レベル+0)の圧縮後データ長を取得する。┬アトミックでなくて構わないので、直接参照可能です。
					int dstLen1 = stMT.dstLen[divLev + 1];		//(分割レベル+1)の圧縮後データ長を取得する。┘
					if(!dstLen0 || !dstLen1) { break; }		//(分割レベル+0)が未完了,又は,(分割レベル+1)が未完了ならば抜けて、サブスレッドの次の処理を待つ。
					if((dstLen0 > 0) &&				//(分割レベル+0)が分割可能で…
					   (dstLen1 > 0) &&				//(分割レベル+1)が分割可能で…
					   (dstLen0 < dstLen1)) { goto L_EXIT; }	//圧縮後データ長が増加傾向に転じたら、これ以上細かく分割しても無駄だと判断して、処理を打ち切る。
				}
			}
L_EXIT:			stMT.reqExit = 1;							//{{2015/02/02コメント追加:(srcLen=1)の場合の処理から分岐してきた時はこの処理はダミーとなる。}}
			while(stMT.numThread) { WaitForSingleObject(stMT.hEvent, INFINITE); }	//{{2015/02/02コメント追加:(srcLen=1)の場合の処理から分岐してきた時はサブスレッドを作成していないのでstMT.numThreadは変化されておらずこの処理はダミーとなる。}}
			CloseHandle(stMT.hEvent);
			divCnt = (1 << divLev);
		}
		//--- 圧縮後データを出力する処理 ---
		{
			dstLen = 0;
			for(iBlk = 0; iBlk < divCnt; iBlk++) {
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
				newMsgLen = fprintf(stderr, "\rout srcLen=%d dstLen=%d divCnt=%d (%d/%d)", srcLen, dstLen, divCnt, iBlk+1, divCnt);
				if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } oldMsgLen = newMsgLen;
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
				//このブロックを圧縮する。
				blkPos = (int)((int64_t)srcLen * (int64_t)(iBlk + 0) / (int64_t)divCnt);		//┬この二行の計算はint64_t型へのキャスト必須です。もしint型のまま計算すると、
				blkLen = (int)((int64_t)srcLen * (int64_t)(iBlk + 1) / (int64_t)divCnt) - blkPos;	//┘数MB以上のファイルを圧縮しようとした時にオーバーフローして異常終了します。
				tmpLen = BytePairEncodingEncoder_EncodeSub(pEncoder, &src[blkPos], blkLen, &dst[dstLen], dstCap - dstLen);
				if(tmpLen < 0) { DIE(); }	//'最適な分割数を求める処理'で'圧縮可能'と判断されたのに、同じ条件で'圧縮不可'と判断される事は有り得ない。
				dstLen += tmpLen;		//圧縮後データの出力サイズを増やす。
			}
		}
		//ワークメモリを開放する。
		free(pEncoder);
	}
	//(文字に割り当てた符号の数=0)を出力する。デコーダはこれを見て、終端ブロックである事を判断する。
	// - ここで行う'dstLen++'は、'最適な分割数を求める処理'には含まれていないので、出力バッファの有無に関係無く行う必要が有る。
	//   もし出力バッファが指定されていない時にこの処理を行わないと、出力バッファが指定されていない時に(-1)の結果差異が生じる。
	if(dstLen < dstCap) { dst[dstLen] = 0; } dstLen++;
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
	newMsgLen = fprintf(stderr, "\rend srcLen=%d dstLen=%d", srcLen, dstLen);
	if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } putc('\n', stderr);
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
	//圧縮後データ長を返す。
	return dstLen;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#else //defined(_WIN32) && defined(_MT)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//通常版		｢ﾌﾟﾛｼﾞｪｸﾄの設定｣⇒｢C/C++｣⇒｢ｺｰﾄﾞ生成｣⇒｢使用するﾗﾝﾀｲﾑﾗｲﾌﾞﾗﾘ｣⇒｢ｼﾝｸﾞﾙｽﾚｯﾄﾞ｣/｢ｼﾝｸﾞﾙｽﾚｯﾄﾞ(ﾃﾞﾊﾞｯｸﾞ)｣を選択した時はこちらを使用します｡
int BytePairEncodingEncoder_Encode(const void* _src, int srcLen, void* _dst, int dstCap) {
	const unsigned char* src = _src;
	      unsigned char* dst = _dst;
	int dstLen = 0;	//(srcLen=0)だった場合のために(dstLen=0)としておく。
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
	int newMsgLen, oldMsgLen = 0;
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
	//圧縮元データが空でなければ…
	if(srcLen) {
		int iBlk, divCnt, blkPos, blkLen, tmpLen;
		//ワークメモリを確保する。
		ST_BytePairEncodingEncoder* pEncoder = malloc(sizeof(ST_BytePairEncodingEncoder) + srcLen);
		if(!pEncoder) { DIE(); }
		//--- 最適な分割数を求める処理 ---
		{
			int minDivCnt = 1;	//圧縮後データ長が最小となる分割数
			int minDstLen = -1;	//圧縮後データ長
			//圧縮後データ長が最小となる分割数と、圧縮後データ長を求める。
			// - 分割した各ブロックに対し再帰して最適な分割数を求める方法も試して見たが、遅すぎて断念した。
			//   数百キロバイト程度のデータを圧縮しようとするだけでも、終わらないぐらいに遅くなってしまう。
			//   仕方無く、一段階だけの分割にした。ファイルの全体の傾向が同じであれば、これでも良いだろう。
			for(divCnt = 1; divCnt <= srcLen; divCnt <<= 1) {
				dstLen = 0;
				for(iBlk = 0; iBlk < divCnt; iBlk++) {
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
					newMsgLen = fprintf(stderr, "\rtry srcLen=%d minDstLen=%d minDivCnt=%d divCnt=%d (%d/%d)", srcLen, minDstLen, minDivCnt, divCnt, iBlk+1, divCnt);
					if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } oldMsgLen = newMsgLen;
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
					//このブロックの圧縮後データ長を求め、加算する。
					blkPos = (int)((int64_t)srcLen * (int64_t)(iBlk + 0) / (int64_t)divCnt);		//┬この二行の計算はint64_t型へのキャスト必須です。もしint型のまま計算すると、
					blkLen = (int)((int64_t)srcLen * (int64_t)(iBlk + 1) / (int64_t)divCnt) - blkPos;	//┘数MB以上のファイルを圧縮しようとした時にオーバーフローして異常終了します。
					tmpLen = BytePairEncodingEncoder_EncodeSub(pEncoder, &src[blkPos], blkLen, NULL, 0);
					if(tmpLen < 0) { goto L_NEXT; }	//'圧縮不可'ならば、この分割数の処理を打ち切り、次の分割数の処理へ進める。
					dstLen += tmpLen;
				}
				//圧縮後データ長が増加傾向に転じたら、これ以上細かく分割しても無駄だと判断して、処理を打ち切る。
				if((unsigned)dstLen > (unsigned)minDstLen) { break; }
				//圧縮後データ長が最小となる分割数と、圧縮後データ長を更新する。
				minDivCnt = divCnt;	//圧縮後データ長が最小となる分割数
				minDstLen = dstLen;	//圧縮後データ長
			L_NEXT:;//'圧縮不可'と判断した場合の分岐位置
			}
			if(minDstLen < 0) { DIE(); }	//(圧縮元データ長/255)以下のブロック長に分割すれば、(サイズが増えたとしても)'圧縮可能'と判断されるはずなので、最後まで'圧縮不可'と判断される事は有り得ない。
			divCnt = minDivCnt;	//分割数
		}
		//--- 圧縮後データを出力する処理 ---
		{
			dstLen = 0;
			for(iBlk = 0; iBlk < divCnt; iBlk++) {
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
				newMsgLen = fprintf(stderr, "\rout srcLen=%d dstLen=%d divCnt=%d (%d/%d)", srcLen, dstLen, divCnt, iBlk+1, divCnt);
				if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } oldMsgLen = newMsgLen;
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
				//このブロックを圧縮する。
				blkPos = (int)((int64_t)srcLen * (int64_t)(iBlk + 0) / (int64_t)divCnt);		//┬この二行の計算はint64_t型へのキャスト必須です。もしint型のまま計算すると、
				blkLen = (int)((int64_t)srcLen * (int64_t)(iBlk + 1) / (int64_t)divCnt) - blkPos;	//┘数MB以上のファイルを圧縮しようとした時にオーバーフローして異常終了します。
				tmpLen = BytePairEncodingEncoder_EncodeSub(pEncoder, &src[blkPos], blkLen, &dst[dstLen], dstCap - dstLen);
				if(tmpLen < 0) { DIE(); }	//'最適な分割数を求める処理'で'圧縮可能'と判断されたのに、同じ条件で'圧縮不可'と判断される事は有り得ない。
				dstLen += tmpLen;		//圧縮後データの出力サイズを増やす。
			}
		}
		//ワークメモリを開放する。
		free(pEncoder);
	}
	//(文字に割り当てた符号の数=0)を出力する。デコーダはこれを見て、終端ブロックである事を判断する。
	// - ここで行う'dstLen++'は、'最適な分割数を求める処理'には含まれていないので、出力バッファの有無に関係無く行う必要が有る。
	//   もし出力バッファが指定されていない時にこの処理を行わないと、出力バッファが指定されていない時に(-1)の結果差異が生じる。
	if(dstLen < dstCap) { dst[dstLen] = 0; } dstLen++;
#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
	newMsgLen = fprintf(stderr, "\rend srcLen=%d dstLen=%d", srcLen, dstLen);
	if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } putc('\n', stderr);
#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
	//圧縮後データ長を返す。
	return dstLen;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#endif//defined(_WIN32) && defined(_MT)
