/*
 *	clipbpe.c
 *
 *	Byte Pair Encoding
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015-2016 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)の場合に終了しなかったバグを修正しました。
 *	* Tue Nov 03 21:42:14 JST 2015 Naoyuki Sawa
 *	- 「Boehm GC」をマルチスレッド対応にした事に伴い、当モジュール内の_beginthread()を_beginthreadex()に変更しました。
 *	  詳細は、/clip/tool/gc/README.TXT の同日のコメントを参照して下さい。
 *	* Sat Nov 14 21:55:38 JST 2015 Naoyuki Sawa
 *	- マルチスレッド版の実装を修正しました。主な変更点は、以下の通りです。
 *	- BytePairEncodingEncoder_Encode()の'CloseHandle(stMT.hEvent)'が、BytePairEncodingEncoder_EncodeTry()の最後の'SetEvent(pMT->hEvent)'よりも先に行われる可能性が有り、
 *	  CloseHandle()よりも後にSetEvent()が行われる可能性の有るバグが有りました。本日、マルチスレッド版の実装を修正して、この不具合は無くなりました。
 *	  上記の不具合修正を含めて、マルチスレッド版の処理内容を見直して、整理しました。
 *	- これまでは、プロジェクトの設定によって、シングルスレッド版(通常版)と、マルチスレッド版を、自動的に切り替えてビルドしていました。
 *	  今後は、シングルスレッド版の関数(BytePairEncodingEncoder_EncodeST)とマルチスレッド版の関数(BytePairEncodingEncoder_EncodeMT)を、明示的に呼び分けられるようにしました。
 *	  シングルスレッド版とマルチスレッド版を呼び分けられるようにした理由は、/clip/tool/dpbpe/main.c の同日のコメントを参照して下さい。
 *	  尚、BytePairEncodingEncoder_Encodeをマクロ定義して、自動的な切り替えにも対応していますので、既存のアプリケーションのソースを変更する必要は有りません。
 *	* Fri Sep 16 21:30:10 JST 2016 Naoyuki Sawa
 *	- ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
 *	  BytePairEncodingEncoder_PrintProgressが0以外ならばBytePairEncodingEncoder_EncodeST(),及び,BytePairEncodingEncoder_EncodeMT()が進捗表示を行い、0ならば進捗表示を行いません。
 *	  これまではBYTEPAIRENCODINGENCODER_PRINTPROGRESSによってコンパイル時に決定していたため実行時に選択出来ませんでしたが、今回の変更によって実行時に選択出来るようになりました。
 *	  そうした理由は、上記の関数を使用するツール(主にdLedSeqC.exe)がオプションによって進捗表示を抑制しても、呼び出し先の上記関数が進捗表示を行ってしまう問題が生じたからです。
 *	  今後は、上記の関数を利用するツールが明示的にBytePairEncodingEncoder_PrintProgressを設定して、進捗表示の有無を選択して下さい。
 *	  尚、BytePairEncodingEncoder_PrintProgressの初期値は、これまでの動作との互換性のために、Windowsならば1(=進捗表示有り)、Windows以外(P/ECEも含む)ならば0(=進捗表示無し)としてあります。
 *	* Thu Sep 29 21:37:05 JST 2016 Naoyuki Sawa
 *	- Hewではエンコーダーを含めないようにしました。
 */
#include "clip.h"

#ifndef __RENESAS__	//{{2016/09/29追加:Hewではエンコーダーを含めないようにしました。}}
/****************************************************************************
 *	BytePairEncodingエンコーダー
 ****************************************************************************/
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#ifdef  WIN32
//#define BYTEPAIRENCODINGENCODER_PRINTPROGRESS //このシンボルを定義するとBytePairEncodingEncoder_Encode()が標準エラー出力に進捗表示を表示する。この行をコメントアウトすれば表示しない。
//#endif//WIN32
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
#ifdef  WIN32
int BytePairEncodingEncoder_PrintProgress = 1;	//進捗表示有り
#else //WIN32
int BytePairEncodingEncoder_PrintProgress;	//進捗表示無し
#endif//WIN32
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
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;
}
/*--------------------------------------------------------------------------*/
//全体を一度で圧縮する関数
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//シングルスレッド版	｢ﾌﾟﾛｼﾞｪｸﾄの設定｣⇒｢C/C++｣⇒｢ｺｰﾄﾞ生成｣⇒｢使用するﾗﾝﾀｲﾑﾗｲﾌﾞﾗﾘ｣⇒｢ｼﾝｸﾞﾙｽﾚｯﾄﾞ｣/｢ｼﾝｸﾞﾙｽﾚｯﾄﾞ(ﾃﾞﾊﾞｯｸﾞ)｣を選択した時はこちらを使用します｡
int BytePairEncodingEncoder_EncodeST(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)としておく。
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
//	int newMsgLen, oldMsgLen = 0;
//#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	int newMsgLen, oldMsgLen = 0;	//進捗表示用。BytePairEncodingEncoder_PrintProgressが0(進捗表示無し)の場合は参照しない。
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'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++) {
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#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 //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
					if(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;
					}						//}}進捗表示用
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'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++) {
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#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 //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
				if(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;
				}						//}}進捗表示用
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'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++;
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#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 //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	if(BytePairEncodingEncoder_PrintProgress) {	//{{進捗表示用
		newMsgLen = fprintf(stderr, "\rend srcLen=%d dstLen=%d", srcLen, dstLen);
		if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } putc('\n', stderr);
	}						//}}進捗表示用
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	//圧縮後データ長を返す。
	return dstLen;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//マルチスレッド版	｢ﾌﾟﾛｼﾞｪｸﾄの設定｣⇒｢C/C++｣⇒｢ｺｰﾄﾞ生成｣⇒｢使用するﾗﾝﾀｲﾑﾗｲﾌﾞﾗﾘ｣⇒｢ﾏﾙﾁｽﾚｯﾄﾞ｣/｢ﾏﾙﾁｽﾚｯﾄﾞ(ﾃﾞﾊﾞｯｸﾞ)｣を選択した時はこちらを使用します｡
#if     defined(_WIN32) && defined(_MT)
//{{2015/11/14変更:マルチスレッド版の実装を修正しました。
//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;
////{{2015/11/03変更:「Boehm GC」をマルチスレッド対応にした事に伴い、当モジュール内の_beginthread()を_beginthreadex()に変更しました。詳細は、/clip/tool/gc/README.TXT の同日のコメントを参照して下さい。
////static void BytePairEncodingEncoder_EncodeTry(volatile ST_BytePairEncodingEncoderMT* pMT) {
////↓2015/11/03変更:「Boehm GC」をマルチスレッド対応にした事に伴い、当モジュール内の_beginthread()を_beginthreadex()に変更しました。詳細は、/clip/tool/gc/README.TXT の同日のコメントを参照して下さい。
//static unsigned __stdcall BytePairEncodingEncoder_EncodeTry(volatile ST_BytePairEncodingEncoderMT* pMT) {
////}}2015/11/03変更:「Boehm GC」をマルチスレッド対応にした事に伴い、当モジュール内の_beginthread()を_beginthreadex()に変更しました。詳細は、/clip/tool/gc/README.TXT の同日のコメントを参照して下さい。
//	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);				//{{2015/11/14コメント追記:BytePairEncodingEncoder_Encode()の'CloseHandle(stMT.hEvent)'が、BytePairEncodingEncoder_EncodeTry()の最後の'SetEvent(pMT->hEvent)'よりも先に行われる可能性が有り、CloseHandle()よりも後にSetEvent()が行われる可能性の有るバグが有りました。本日、マルチスレッド版の実装を修正して、この不具合は無くなりました。}}
////{{2015/11/03追加:「Boehm GC」をマルチスレッド対応にした事に伴い、当モジュール内の_beginthread()を_beginthreadex()に変更しました。詳細は、/clip/tool/gc/README.TXT の同日のコメントを参照して下さい。
//	return 0;
////}}2015/11/03追加:「Boehm GC」をマルチスレッド対応にした事に伴い、当モジュール内の_beginthread()を_beginthreadex()に変更しました。詳細は、/clip/tool/gc/README.TXT の同日のコメントを参照して下さい。
//}
//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++) {			//論理プロセッサの数だけ…
////{{2015/11/03変更:「Boehm GC」をマルチスレッド対応にした事に伴い、当モジュール内の_beginthread()を_beginthreadex()に変更しました。詳細は、/clip/tool/gc/README.TXT の同日のコメントを参照して下さい。
////				_beginthread(BytePairEncodingEncoder_EncodeTry, 0, (void*)&stMT);	//サブスレッドを作成する。
////↓2015/11/03変更:「Boehm GC」をマルチスレッド対応にした事に伴い、当モジュール内の_beginthread()を_beginthreadex()に変更しました。詳細は、/clip/tool/gc/README.TXT の同日のコメントを参照して下さい。
//				HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, BytePairEncodingEncoder_EncodeTry, (void*)&stMT, 0, NULL);
//				if(!hThread) { DIE(); }
//				CloseHandle(hThread);	//スレッドの終了待ちはイベントを使っているのでスレッドハンドルは必要無い。従ってスレッドの終了を待たずすぐにスレッドハンドルを閉じて構わない。
////}}2015/11/03変更:「Boehm GC」をマルチスレッド対応にした事に伴い、当モジュール内の_beginthread()を_beginthreadex()に変更しました。詳細は、/clip/tool/gc/README.TXT の同日のコメントを参照して下さい。
//			}
//			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);	//{{2015/11/14コメント追記:BytePairEncodingEncoder_Encode()の'CloseHandle(stMT.hEvent)'が、BytePairEncodingEncoder_EncodeTry()の最後の'SetEvent(pMT->hEvent)'よりも先に行われる可能性が有り、CloseHandle()よりも後にSetEvent()が行われる可能性の有るバグが有りました。本日、マルチスレッド版の実装を修正して、この不具合は無くなりました。}}
//			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;
//}
//↓2015/11/14変更:マルチスレッド版の実装を修正しました。
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=圧縮後データ長
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
//	int			  iBlk[32/*divLev*/];
//#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	int			  iBlk[32/*divLev*/];	//進捗表示用。BytePairEncodingEncoder_PrintProgressが0(進捗表示無し)の場合は参照しない。
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//{{2016/09/16コメント変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//	HANDLE			hEvent[2];		//[0]=サブスレッドがdstLen[*]を変更した事をメインスレッドへ通知するためのイベント。[1]=サブスレッドがiBlk[*]を変更した事をメインスレッドへ通知するためのイベント。実装を単純にするためにBYTEPAIRENCODINGENCODER_PRINTPROGRESSが定義されていない場合も[1]を作成するが利用しない。
//↓2016/09/16コメント変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	HANDLE			hEvent[2];		//[0]=サブスレッドがdstLen[*]を変更した事をメインスレッドへ通知するためのイベント。[1]=サブスレッドがiBlk[*]を変更した事をメインスレッドへ通知するためのイベント。実装を単純にするためにBytePairEncodingEncoder_PrintProgressが0(進捗表示無し)の場合も[1]を作成するが利用しない。
//}}2016/09/16コメント変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	int			reqExit;		//メインスレッドから、サブスレッドへの終了要求フラグ	サブスレッドが取得した分割数が圧縮元データ長を超過した場合も終了します。
} ST_BytePairEncodingEncoderMT;
static unsigned __stdcall BytePairEncodingEncoderMT_EncodeTry(volatile ST_BytePairEncodingEncoderMT* pMT) {
	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(); }
	//メインスレッドの終了判断のために、サブスレッドの優先度を下げる。
	// - メインスレッドがサブスレッドのイベントを待つ形なので、メインスレッドの方が優先度が高いのが適切である。
	//   もしメインスレッドとサブスレッドの優先度が同じままにすると、メインスレッドの終了判断が遅れて、全体の処理時間が無駄に伸びてしまう場合が有る。
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
	for(;;) {
		divLev = InterlockedIncrement((int*)&pMT->divLev);	//次に実行する分割レベルを取得する。
		divCnt = (1 << divLev);
		if(divCnt > srcLen) { break; }	//サブスレッドが取得した分割数が圧縮元データ長を超過した場合も終了します。pMTの内容を変更していないので、SetEvent(pMT->hEvent[0/*dstLen*/])は不要です。
		dstLen = 0;
		for(iBlk = 0; iBlk < divCnt; iBlk++) {
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
//			pMT->iBlk[divLev] = iBlk;
//			SetEvent(pMT->hEvent[1/*iBlk*/]);
//#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
			if(BytePairEncodingEncoder_PrintProgress) {	//{{進捗表示用
				pMT->iBlk[divLev] = iBlk;
				SetEvent(pMT->hEvent[1/*iBlk*/]);
			}						//}}進捗表示用
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'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(divLev) {							//┐現在の分割レベルが0でなく、(分割レベル-1)が分割可能で、現在の圧縮後データ長が(分割レベル-1)の圧縮後データ長を超えたら、処理を打ち切る。
				int dstLen2 = pMT->dstLen[divLev - 1];			//│pMT->dstLen[divLev]に格納する値は、pMT->dstLen[divLev-1]よりも大きな値であれば正確な値でなくて構わないので、この時点でのdivLevを格納する事にした。
				if((dstLen2 > 0) && (dstLen > dstLen2)) { break; }	//│メインスレッドは、隣り合う分割レベルについて終了条件を満たした事を検出して、(分割レベル-1)を採用するだろう。(厳密には、(分割レベル-1)以前の分割レベルが後で完了して終了条件を満たした場合はそちらが採用されるだろうが、いずれにせよ正しい結果となる。)
			}								//┘この四行は、終わり際でブロックを処理しているスレッドが少しでも早く終了するための高速化の工夫であり、この4行を削除しても結果は同じです。
		    //}}この範囲は高速化のためだけの処理です。この範囲を削除しても結果は変わりません。
			if(pMT->reqExit) { goto L_EXIT; }	//pMT->reqExitがセットされているという事は、メインスレッドはもうpMT->hEventを待っていないので、SetEvent(pMT->hEvent[0/*dstLen*/])は不要です。
		}
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
//		pMT->iBlk[divLev] = iBlk;
//		SetEvent(pMT->hEvent[1/*iBlk*/]);
//#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
		if(BytePairEncodingEncoder_PrintProgress) {	//{{進捗表示用
			pMT->iBlk[divLev] = iBlk;
			SetEvent(pMT->hEvent[1/*iBlk*/]);
		}						//}}進捗表示用
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
		pMT->dstLen[divLev] = dstLen;
		SetEvent(pMT->hEvent[0/*dstLen*/]);
	}
L_EXIT:	//ワークメモリを開放する。
	free(pEncoder);
	return 0;
}
int BytePairEncodingEncoder_EncodeMT(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)としておく。
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
//	int newMsgLen, oldMsgLen = 0;
//#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	int newMsgLen, oldMsgLen = 0;	//進捗表示用。BytePairEncodingEncoder_PrintProgressが0(進捗表示無し)の場合は参照しない。
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	//圧縮元データが空でなければ…
	if(srcLen) {
		int iBlk, divCnt, divLev = 0;	//(srcLen=1)だった場合のために(divLev=0)としておく。
		//ワークメモリを確保する。
		ST_BytePairEncodingEncoder* pEncoder = malloc(sizeof(ST_BytePairEncodingEncoder) + srcLen);
		if(!pEncoder) { DIE(); }
		//--- 最適な分割数を求める処理 ---
		if(srcLen != 1) {	//(srcLen=1)を除外する理由は、'Mon Feb 02 21:59:02 JST 2015'のコメントを参照せよ。
			volatile ST_BytePairEncodingEncoderMT stMT;
			SYSTEM_INFO si;
			HANDLE hThread[MAXIMUM_WAIT_OBJECTS/*=64*/];	//サブスレッド数の最大数は、WaitForMultipleObjects()で一度に待てる最大数(64)とした。
			int i, numThread;
			//構造体を初期化する。
			memset((void*)&stMT, 0, sizeof stMT);
			stMT.src    = src;
			stMT.srcLen = srcLen;
			stMT.divLev = -1;	//次に実行する分割レベル-1	InterlockedIncrement()を使ってアクセスし分割数divCnt=(1<<戻り値)を実行する。初回の戻り値を0とするために-1に初期化せよ。
			stMT.hEvent[0/*dstLen*/] = CreateEvent(NULL, FALSE/*自動リセットオブジェクト*/, FALSE/*非シグナル状態*/, NULL);
//{{2016/09/16コメント変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//			stMT.hEvent[1/*iBlk*/]   = CreateEvent(NULL, FALSE/*自動リセットオブジェクト*/, FALSE/*非シグナル状態*/, NULL);	//実装を単純にするためにBYTEPAIRENCODINGENCODER_PRINTPROGRESSが定義されていない場合も[1]を作成するが利用しない。
//↓2016/09/16コメント変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
			stMT.hEvent[1/*iBlk*/]   = CreateEvent(NULL, FALSE/*自動リセットオブジェクト*/, FALSE/*非シグナル状態*/, NULL);	//実装を単純にするためにBytePairEncodingEncoder_PrintProgressが0(進捗表示無し)の場合も[1]を作成するが利用しない。
//}}2016/09/16コメント変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
			//サブスレッドを作成する。
			GetSystemInfo(&si);
			numThread = si.dwNumberOfProcessors;
			if(numThread < 1) { DIE(); }	//有り得ないはずだが、念のため確認する。
			if(numThread > ARRAY_SIZE(hThread)) { numThread = ARRAY_SIZE(hThread); }
			for(i = 0; i < numThread; i++) {
				hThread[i] = (HANDLE)_beginthreadex(NULL, 0, BytePairEncodingEncoderMT_EncodeTry, (void*)&stMT, 0, NULL);
				if(!hThread[i]) { DIE(); }
			}
			for(;;) {
				i = WaitForMultipleObjects(2, (HANDLE*)stMT.hEvent, FALSE, INFINITE);	//サブスレッドの次の処理を待つ。	キャストはvolatileの警告抑制のためです。動作には関係有りません。
				switch(i - WAIT_OBJECT_0) {
				default:DIE();
				case 0/*dstLen*/:
					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; }	//圧縮後データ長が増加傾向に転じたら、これ以上細かく分割しても無駄だと判断して、処理を打ち切る。
					}
					break;
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#ifdef  BYTEPAIRENCODINGENCODER_PRINTPROGRESS //{{進捗表示用
//				case 1/*iBlk*/:
//					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;
//					}
//					break;
//#endif//BYTEPAIRENCODINGENCODER_PRINTPROGRESS //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
				case 1/*iBlk*/:
					if(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;
						}
					}						//}}進捗表示用
					break;
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
				}
			}
L_EXIT:			//サブスレッドをクリーンアップする。
			stMT.reqExit = 1;
			i = WaitForMultipleObjects(numThread, hThread, TRUE, INFINITE);
			if((unsigned)(i - WAIT_OBJECT_0) >= (unsigned)numThread) { DIE(); }	//バグ
			for(i = 0; i < numThread; i++) { CloseHandle(hThread[i]); }
			//構造体をクリーンアップする。
			CloseHandle(stMT.hEvent[0/*dstLen*/]);
//{{2016/09/16コメント変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//			CloseHandle(stMT.hEvent[1/*iBlk*/]);	//実装を単純にするためにBYTEPAIRENCODINGENCODER_PRINTPROGRESSが定義されていない場合も[1]を作成するが利用しない。
//↓2016/09/16コメント変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
			CloseHandle(stMT.hEvent[1/*iBlk*/]);	//実装を単純にするためにBytePairEncodingEncoder_PrintProgressが0(進捗表示無し)の場合も[1]を作成するが利用しない。
//}}2016/09/16コメント変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
		}
		divCnt = (1 << divLev);
		//--- 圧縮後データを出力する処理 ---
		{
			int blkPos, blkLen, tmpLen;
			dstLen = 0;
			for(iBlk = 0; iBlk < divCnt; iBlk++) {
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#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 //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
				if(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;
				}						//}}進捗表示用
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'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++;
//{{2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
//#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 //}}進捗表示用
//↓2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	if(BytePairEncodingEncoder_PrintProgress) {	//{{進捗表示用
		newMsgLen = fprintf(stderr, "\rend srcLen=%d dstLen=%d", srcLen, dstLen);
		if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } putc('\n', stderr);
	}						//}}進捗表示用
//}}2016/09/16変更:ローカルシンボル'BYTEPAIRENCODINGENCODER_PRINTPROGRESS'を廃止して、グローバル変数'BytePairEncodingEncoder_PrintProgress'を追加しました。
	//圧縮後データ長を返す。
	return dstLen;
}
//}}2015/11/14変更:マルチスレッド版の実装を修正しました。
#endif//defined(_WIN32) && defined(_MT)
#endif//__RENESAS__	//{{2016/09/29追加:Hewではエンコーダーを含めないようにしました。}}
