/**
 *	@file e:\my-projects\UberLame_src\gpgpu\kernels\\ScanKernelsv2Src.h
 *	@brief file in header, generated from 'e:\my-projects\UberLame_src\gpgpu\kernels\ScanKernelsv2.c'
 *		using BWT / RLE / Huff / Base85 pipe
 *	@date 2016-06-16 19:56:59
 *	@author FileToHeader v2.03 (built Jun 30 2016)
 */

#pragma once
#ifndef __E__MY_PROJECTS_UBERLAME_SRC_GPGPU_KERNELS_SCANKERNELSV2_C_FILE_IN_HEADER_INCLUDED
#define __E__MY_PROJECTS_UBERLAME_SRC_GPGPU_KERNELS_SCANKERNELSV2_C_FILE_IN_HEADER_INCLUDED

/**
 *	@brief file in header, generated from 'e:\my-projects\UberLame_src\gpgpu\kernels\ScanKernelsv2.c'
 */
class CScanKernels_Src {
public:
	/**
	 *	@brief gets size of the data
	 *	@return Returns size of the data, in bytes, not including the terminating zero.
	 */
	static inline size_t n_Size()
	{
		return 23645; // original file 44809 B
	}

	/**
	 *	@brief determines whether the stored string is dynamically allocated
	 *	@return Returns true if the caller of p_Data() needs to free the memory.
	 */
	static inline bool b_Dynamic()
	{
		return true;
	}

	/**
	 *	@brief gets CRC
	 *	@return Returns CRC32 of the stored data.
	 *	@note The stored CRC may differ from the original file if data processing was enabled.
	 */
	static inline uint32_t n_CRC32()
	{
		return 0x8d56d9eb; // original file 0x84c15dd7
	}

	/**
	 *	@brief gets data
	 *
	 *	@return Returns data of the file on success, 0 on failure (not enough memory).
	 *
	 *	@note The data (despite it may be binary), is additionally null terminated to make
	 *		it easier to use (the terminating null is not counted in n_Size()).
	 *	@note See also b_Dynamic().
	 */
	static inline char *p_Data()
	{
		const char *p_s_base85 = "~0RR910RR910{{R31ONa42mk;82mk;84gdfE4gdfE82|tP7ytkO3jhEBA^-pY~~~0"
			"09C81Oo>K2.z}f4+;zs6&Vf_5E~a35*->8As96&A0sC%F)K+P93UkmA}=#2bvG(3J0|}<X.u@0KSwe+IZHu8Lw"
			"$pHMPV+9YLPr$PjqiUZB21ZL})(sd{J;y)m2wmc3)XEFlTsMm7iM0d4O_rI!H!JPF{tFdW}$HQdX<4v$eftYsb"
			"ld;p6A;@$+u8*!d4z8G~9,CFoM%1!yj!h=y_,D@<TPCCUv@PBShtBrXCZFJOc%q)1r<RH8gfjBD2cgb54WD28r"
			"g7+v!Ofh,0uzS%|vnM4YsCGZf1QxqUdV<pZqQz(Ibz*Plt+(3{Z_R|8W$vDYzlt7$hzodjLhDpXr$}lGxmBkP("
			"1<U>8GT1{4q-4EQ{=-pnjLX$3G%r;726gJ5F{rynh4PHc_>BwIG8>h8r}@Z,y;JND^HgcS{Kl%7-gTgf3z%fGB"
			"FJY6IO~W%DnBZaCm9a3gQNI=J8_NaU1l(gF&n7CNr6<{f^j5BlISd~n1.i^GXqRyrV3|u5FwHzgq-d$fkO&R32"
			"ime*hn7ZkqHR,8Z!x6GFwb!lLI)+s&X)f83P2.A,vAr5UNCcEwu1B&vYQLawqndGjn,6hQUI-rUIjoiyfG@(k9"
			"KA%2gUn>H}TDEe81{2#~Eg9AZd92{<dkoa95MkW23~LzpAsX+}gSlaTTz*b).)(#F9iv.AcMA(Och6N1Pc!CFx"
			"gYeBfdOcR2s+^}k!$ShN!)U;,>hMSO0#&RH2F=q6Wl=TpWG8|I{GZq<y.r%_mrZe;c<~PagL23tfg^{Kq3_Dc!"
			"SbxX<U#$OipX-95<qOll|IIR}$xQEjd3>L1O8zzYtSC*7pE13~z;QkD{D|lt$<07Yq2=W_TO<4j!SgW9sm(D65"
			"S*hi+;OD3!_=5=.KfbL,i@l(W<l&Z5{YCIbGpR4{5ydnVfdzDU,mZL$U(8eS{!=@@MAHf2MiqK,@h4&RKn2(.p"
			"dmizeAWH%vl0)lUf$-BWSWL%Xp;a5Zc{T8<Z..l|h^(d4<A)PE#}Yt)(zwt|OmkJDfkd4)#3+!oizBCpEC*Wud"
			"hgrk9<XJLDl+cU_4$._xpW#!sLVgE@mSucjQNIL->7.rEUSu6#Q(4O>Hn!DLx39FlUI8*J_{&,2ic,2_SOBZ6V"
			"UFr%Be3Ls#1t>D+3O)>&P!LK6{j(B7^Mu@~J_ZJDlI4eO~G+gHN6D}B~z^*uErP5)o$RJfIe28+4wX2RQ5LiE*"
			"+lx@kc3{.mnd&$D2<Arw8+;ZC(+zn~x=$R=<ouo7O94rSQXQ&rp$I#J+$N~YI-a8qz%@CgFr^|3+D><(aVioNu"
			"Vjn%Z4N&ePGd7%X,#7Q=,9BmZXHcvf6%VboWrHU9214P4T^JG@D.UDEP,$eL9SvDiRKM>MM,fvWzIL#HwMg&zq"
			"ZXmEP~6%s&SQEWzyiSDHaP*D@-0lg;K>S6_,dwwvBv8PS2w&jrgN-4ok3cxRyY!4K{_Y5|~Bd!r+{v0&rJ.>jl"
			"bixYQC5AxtZ2NF^&x-)%aubQVjL!crKeP2XDdND>h#ks.<GDsSMxV;2>U71~l@oUzy>;Vqz.6N0o8n%rVc3#2K"
			")5ox9<TfiE#4Vnh<N8B21FlwBc,7|(fAB+1xdf~VgrX63<PmfE5CKPe9_PnEiV$cz&rBSNz)Zp2l&5HZA1~,~Z"
			"G6k~VAT6bqur@<U{J{=Wgi6ziAVTGcQ#mpTG^,KA.6NzOfdfhWYxw^|E*y>|PHW%G4Mn|$B=*I,E(uywAX6}rF"
			"jEBJvIO9!51ETGD(i}r)|NX$cAln~P|Beyv~1P+y=W|$$xPPC)Ga7@q^IqEXE0o5i<+i9g01a)ttS6K$*Sk,d6"
			"*d(*+.WD!)AdD<0(11M){xNw#LRyuxQzNr}at+GEP{-ilC}kgeL^$jvd)J);+{oCUVTQgz_-cr|;67,5x@dPIC"
			"Z_W=8*5T6LZmvii)4OH9v3TQ6(#8)WU0J-NU|O|E-Ri*K-;AV9-2@M>,aaiL5q=9NMSgycY,V#K5paiKYi8hMh"
			"q(,Nb2<TH@zOvjLuE>8EVICvZv{sXIEEXGRFlHeJa{7fx9pmzn4#lvP-U92zXe1fiEkR_1o5J0SOo0.F9!&,>O"
			"3$i#--zTYhiwxMy.-p2ajo4}Ko4.cVN26z8&Fo|yHjK*9l)-8Q;HC;-)|l!B,pIl5aHYUm(h0K#*fiUyZOZVK!"
			"zFMm&PETuHh@wW##8GP=rP3|GD*VSqb0y={^J15Xz!jG4t,QWq(S#bXDsP3Cz*_m;|-{.@Ug8l>p7Sw>(naaD$"
			"M@(KSA}Laf%p)ZX{5tBUr,-KbH=U@%}#q._++XxsOoyD1ii~2|S=BdEr2ULw6A%N>,p15iHmujQ*qb5^~F(D!J"
			"T|0V7SY7ckX6D=egjMV4,e$DIxn5LMM>F*yiV4GGL,xPFpOQVCJPI4OjjB;#WimP<^e_Jx%!K&ddn&!q@-nODW"
			"8K<#jvM)xC-^jvOibh0oQ6Pk6Jb14y0#7_;sa6XxWyr(JYZi2=>ai+AA8HiZ|v=vMem&Y$!X6Oe!wg.v~2wecW"
			"N+4E)xGr#Ng4zq;Aqrrw1mh){2wVk_AxzSQgeL,%F2T23+Ba9=$QRoWrlWh!|G@J6<(<62CpEBmgUCfl^b7GC^"
			"c~}1aIDQKL7.z|fB6A__&Z#WAi08HfP{Oz!Mb7Na8m^^Qw4A@7+Em=UwFkIs64AO#y*nHQy0X{dUglR>kZ{u4Y"
			"_1O7brh5r3aAd8>BJ+krx{(6Y+xP4sK$~k{>~jl*}Z$!%rz09qv%M!F7!(=nZa1x|GTxcP<EX9#f2v{K2EFGWE"
			"f|aM#u}cQXf=ap(;$6uf1x;0k)>h&|}#BO~F^4b(*R$LtIB1XPPk^8%>a,8x{|1mLO*FkME!7>*sFvJL*YOPI#"
			"Ze;ad)@P>bY(t-,8pU7G568MKsV1y-kM-OqxMs).|3HxIu%nD)2P;Q{_a*>fQTrjk<3KXbI|Ddf6U-t#p3S>;b"
			"<}uN6P~_+i<wJ_5G$k3BIgiaEVJe0GGLi*(9nwx3^bH<<(B$>P-2r}pjxrp}=O}@yLp1Xa.Z*-dcmX3tL8f<5A"
			"mJEf3&b*91&IkcXS#v289u;OEM36Itd0U-u-|Y#!-s_8>JN+RG5kNT+dMlHoQ%j2AqmE2xfuIlg-T{_Q!Gf~T8"
			"2tzoi*f,HU2m.0t*92QKz(|yTVQiqb1G.rnqpHYJKlq8|o.O,|IY=7*yA3w|49caN29sT6YfU&Y%@aBu2roTw{"
			"18Fwfr^w^VI7e!,o4Np=F@G@wDTy}}XuZW~I_LKVdjFY7Q^Fw4YKS@*~P6(BwPjvw-H{9bQ*MiQ5s-jcYak!9p"
			"~hqz>>Z<LTAO5@KfMn6m^7.3cyPvz#kr+huyhR.tsk<LzF_iWZo.@;;X9!_AFt,odEIYSPkULp9ydG@)2IL+=I"
			"0nmD#e4|86DN|mNjfV*RVJ9(=S-9wMjLKb^yHMUV=DbKig)$Jd49d}({Ra~g5+uyFnphJuZlRi;@v&KyVC=Nls"
			"5BtHSCQ>,{GV(u&<fCtg35(747j++-#R#UI4pw8fjBnMZ3H1)ACt6;PVZ<hjN<U;U4jrQjGs{(3Ur4JqiCOL8I"
			"jlvAYVY=h3Yd-p=N+i6XOYg>.fdTSA$e1v=vCH.YhJ.hb)|>K}@0rkqA>LkxGqa+X5;zit&<i5V}hcCe#ha7it"
			"^eYr^i(dX3yyjFmw+E|Q29#35u7%sfs)6v#qy#91jhWRey,B<2V}xyZC$utSiAGKdx9B{GQ$qa{;,As|SN0J(_"
			"Lm7uD55eMN!5F%zUu~BH&uVm9ewBi>5X0;+ckh7G-NU$;J2;(sB9RaJv99M$c3!oE%=NT%3>IMBpG2|QnLBHw,"
			"wJ,k_g}%s7K+ARHYHNLyP8)vE+(+j5LuP|_Q32~43ro7jd$ke#1(3~OydEE@IX;3AyWqX>T8bjh8^M35BleiwN"
			"T}OG9KlQ$(6h9|mte$NY2Ze&63mDfP&WZc3^,6O(2l~wcQ4cF40=LdscF8PI.@l3la1Y0jOyTBg)>rFn8mPhQk"
			"H_~1#vc^@qXyMC%_N#6z~UkfYabVSm9qWkG@-Ps4s*YLA!bKFvh,*EepIxIQT,vf40!GAhMxPDNB3@27.X7@)n"
			"@OfR3,RYrB(G!o1(o7WRYvvYcYi(hERJVIQ0.*i#@.G4Ao94cZ>_gk~MfLOp=*I4wh8KS<Nv*fl5Y7*ILM,a+q"
			"4aM92d_5wN#BjNSA2l+y7Lgd}n8nX@8g)Jcp&{mZAL0VE^&JA!%(Ui6g4S7ZyR+coNTL@uV3ZSM$3a0lI9cFO5"
			"Lj3,UP&R<iAki,,6NawQmtJIYXXebZhksq)oM}HeDT2@&Is*xZk;0A(pcZ5>stX,lg80Tt@V&#6zBIkZ4Rs7P7"
			"HcF*@YD1I,{gxnJN)B1@t9O3S3yl08lK2ym{a;gyPz6i-Y{8$.~!1.w6nr@c5LV=BZ~ZrUJGb7psy&s9ZKMq(W"
			"JE)#v>ixd4{fV$1uCJJ.91D4gUyk=M6n&78>r_GbbHX!>~7ttZWxR$$COof~YM)UV<oA(lW911vtT+joYWr8>R"
			"}RQugr-laR;7sAS#nn~}tt(@J3>Cn$lq#%6MeOynV)HeL<PSlNR)3@0dooEz2&Oc%~H+VE,w8Ui>1SA._#v;.>"
			"YlUi9JgySXO1mMmMsG<bzWuhr.Nz.<(C2&e)Fx;k>5FuJZ7o@UG!@Ax%0WxaRmz)dpgJeX8_XgLG7&lN~#u56#"
			"zw%PhyQn8nTx4{f7Y(1(9esem&{FV!u%v^VL1rg-T;-PqHvZtFg{}_audrp0*d50P,AZPypVA&nfodX&rV6AX<"
			",r<x&|5=,BLoa58<jY5c}9~sEP;5zbChNo!cGj~i;(0w$ss,0A-G-~7NC=uq{14|SAx71#t0F|.1ru~oThE4jz"
			"RbWwt}.N#m3hNZ3Yx)2E32BUs9GCYjD~9#4x4{KsRAy2{gv)$BY|LZqOdnjJ10qzoZ$+)K9F9_utwPFyZ(D%>k"
			"mJW#Omn4RZ^4$dTaZ3QRKjLoe+InT|rkNy$)CB7->3T8&E,X(m!(H!(vZN@kR#cLG|A7~X6Cuy+}_eSxiypgTQ"
			"~T_u<rb+&+g1vP^66p%{cwNuIs+BVks3S3<i1mh)8SpspA=Lz$I^8){XaCU;Uu^.)My|CSx97LRiOXDG~#_*1C"
			"u7Hmz8wTq*upQ1RLB4+hW0;s~8pSh,(,mT6<JvRI^2|^yj1VDgBfKh<WGRf5NJllGstuqS!wkdD<YkWUlsC+.0"
			"O@@Nl@=PWBg|c(BG9XmQNF;!p}&lyawX6*T>#$T-X*{.U(QhlnTC0d=v{<fdVZj8(##ISPtZ0xc}7F11mh)fL<"
			"zx6WVV)nAcpyeQvd";
		return (char*)p_Decode_BWT_MTF_RLE_Huff_Base85(p_s_base85, 23645, 7698, 5431);
	}

protected:
	/**
	 *	@brief decompression routine
	 *
	 *	@param[in] p_s_base85 is null-terminated string containing Base-85 encoded compressed data
	 *	@param[in] n_data_size is size of the decompressed data
	 *	@param[in] n_huff_stage_size is size of the compressed data before Huffman encoding
	 *	@param[in] n_bwt_primary_index is primary index for the BWT algorithm
	 *
	 *	@return Returns pointer to the decompressed data on success, 0 on failure.
	 *
	 *	@note The data (although it may be binary), is additionally null terminated.
	 */
	static uint8_t *p_Decode_BWT_MTF_RLE_Huff_Base85(const char *p_s_base85,
		size_t n_data_size, size_t n_huff_stage_size, uint32_t n_bwt_primary_index)
	{
		size_t n_base85_length = strlen(p_s_base85), n_base85_size = 0;
		int p_b85_ic_tab[128] = {0};
		{
			for(int i = 0, j = -10, k = 55, l = -62; i < 85; ++ i, ++ j, ++ k, ++ l)
				p_b85_ic_tab[(j < 0)? k - 7 : (l < 0)? k + j / 26 * 6 : "!#$%&()*+-;<=>.@^_,{|}~"[l]] = i;
			const char *p_s_src = p_s_base85, *p_s_end = p_s_base85 + n_base85_length;
			for(size_t n_diff, n_rem = n_base85_length; p_s_src < p_s_end;
			   p_s_src += n_diff * 4 + 1, n_rem -= n_diff * 4 + 1)
				n_base85_size += (n_diff = (p_b85_ic_tab[*p_s_src] == 84))? 4 : min(n_rem, size_t(5)) - 1;
		}
		size_t n_prehuff_size = max(n_base85_size, n_data_size);
		size_t n_temp_buffer_size = max(n_prehuff_size + n_huff_stage_size,
			n_data_size * (1 + sizeof(uint32_t)));

		uint8_t *p_temp_buffer, *p_data;
		if(!(p_temp_buffer = new(std::nothrow) uint8_t[n_temp_buffer_size]) ||
		   !(p_data = new(std::nothrow) uint8_t[n_data_size + 1])) {
			if(p_temp_buffer)
				delete[] p_temp_buffer;
			return 0;
		}
		p_data[n_data_size] = 0; // null-terminate the data

		{
			uint8_t *p_dst = p_temp_buffer - 1;
			const char *p_s_src = p_s_base85, *p_s_end = p_s_base85 + n_base85_length;
			for(size_t n_rem = n_base85_length; p_s_src != p_s_end; -- n_rem, ++ p_s_src) {
				if(p_b85_ic_tab[*p_s_src] != 84) {
					uint32_t n_block = uint32_t(min(n_rem, size_t(5))), n_code = 0;
					_ASSERTE(n_block >= 2);
					for(unsigned int i = 0; i < 5; p_s_src += ((++ i < n_block)? 1 : 0))
						n_code = n_code * 85 + ((i < n_block)? p_b85_ic_tab[*p_s_src] : 84);
					for(unsigned int i = 1; i < n_block; ++ i, -- n_rem)
						*(++ p_dst) = n_code >> (8 * (4 - i));
				} else
					*(uint32_t*)((p_dst += 4) - 3) = 0;
			}
		}
		{
			const uint8_t *p_huff_src = p_temp_buffer, *p_huff_end = p_huff_src + n_base85_size;
			_ASSERTE(p_huff_src + 16 * sizeof(int32_t) <= p_huff_end);
			const int32_t *p_code_num = (const int32_t*)p_huff_src;
			int p_max_code[16], p_table_off[16], n_code_num = 0;
			for(int i = 0, n_code_word = 0; i < 16; ++ i, n_code_word <<= 1) {
				p_table_off[i] = (n_code_num += p_code_num[i]) - (n_code_word += p_code_num[i]);
				p_max_code[i] = n_code_word;
			}
			const uint8_t *p_symbol = (p_huff_src += 16 * sizeof(int32_t));
			_ASSERTE(p_huff_src + n_code_num <= p_huff_end);
			p_huff_src += n_code_num - 1;
			uint8_t *p_dest = p_temp_buffer + n_prehuff_size, *p_end = p_dest + n_huff_stage_size;
			for(uint8_t n_byte = 0, n_bit_num = 7; p_dest != p_end; ++ p_dest, n_byte <<= 1) {
				for(int i = 0, n_code = 0;; ++ i, n_byte <<= 1) {
					_ASSERTE(i < 16);
					if(!((++ n_bit_num) & 7)) { // every 8
						_ASSERTE(p_huff_src < p_huff_end);
						n_byte = *(++ p_huff_src);
					}
					n_code = (n_code << 1) | (n_byte >> 7);
					if(n_code < p_max_code[i]) {
						_ASSERTE(n_code >= p_max_code[i] - p_code_num[i]); // n_code >= p_min_code[i]
						*p_dest = p_symbol[n_code + p_table_off[i]];
						break;
					}
				}
			}
		}
		{
			const uint8_t *p_rle_src = p_temp_buffer + n_prehuff_size,
				*p_src_end = p_rle_src + n_huff_stage_size;
			for(uint8_t *p_rle_dest = p_temp_buffer; p_rle_src != p_src_end;) {
				uint8_t n_code = *p_rle_src;
				bool b_compressed = n_code & 1;
				int n_run_length = (n_code >> 1) + 2;
				_ASSERTE(p_rle_src + ((b_compressed)? 2 : n_run_length) <= p_src_end);
				for(; -- n_run_length; ++ p_rle_dest)
					*p_rle_dest = (b_compressed)? p_rle_src[1] : *(++ p_rle_src);
				p_rle_src += int(1 << ((b_compressed)? 1 : 0)); // fix an x64 warning here
			}
		}
		{
			uint8_t p_buckets[256] = {0}; // each bucket value encoded as offset to its index
			uint8_t *p_data = p_temp_buffer, *p_end = p_temp_buffer + n_data_size;
			for(; p_data != p_end; ++ p_data) {
				uint8_t n_index = *p_data;
				*p_data = p_buckets[n_index] + n_index;
				for(int i = n_index; i != 0; -- i)
					p_buckets[i] = p_buckets[i - 1] - 1;
				if(n_index)
					p_buckets[0] = *p_data;
			}
		}
		{
			uint32_t p_buckets[257] = {0}, *p_index_list = (uint32_t*)(p_temp_buffer + n_data_size);
			const uint8_t *p_src = p_temp_buffer, *p_end = p_temp_buffer + n_data_size;
			for(uint32_t *p_dest_idx = p_index_list; p_src != p_end; ++ p_src, ++ p_dest_idx)
				*p_dest_idx = (++ p_buckets[*p_src + 1]) - 1; // start accumulating in bucket 1
 			for(int i = 1; i < 255; ++ i) // exclusive prefix sum
				p_buckets[i + 1] += p_buckets[i];
			uint8_t *p_dest = p_data + n_data_size - 1, *p_begin_1 = p_data - 1;
			for(uint32_t i = n_bwt_primary_index; p_dest != p_begin_1; -- p_dest,
			   i = p_index_list[i] + p_buckets[p_temp_buffer[i]])
				*p_dest = p_temp_buffer[i];
		}
		_ASSERTE(!p_data[n_data_size]); // make sure the terminating null was not overwritten

		delete[] p_temp_buffer;
		
		return p_data;
	}
};

#endif // !__E__MY_PROJECTS_UBERLAME_SRC_GPGPU_KERNELS_SCANKERNELSV2_C_FILE_IN_HEADER_INCLUDED
