Editor/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
#nullable disable
using System;

namespace SevenZip.Compression.RangeCoder
{
	struct BitTreeEncoder
	{
		BitEncoder[] Models;
		int NumBitLevels;

		public BitTreeEncoder( int numBitLevels )
		{
			NumBitLevels = numBitLevels;
			Models = new BitEncoder[1 << numBitLevels];
		}

		public void Init()
		{
			for ( uint i = 1; i < (1 << NumBitLevels); i++ )
				Models[i].Init();
		}

		public void Encode( Encoder rangeEncoder, UInt32 symbol )
		{
			UInt32 m = 1;
			for ( int bitIndex = NumBitLevels; bitIndex > 0; )
			{
				bitIndex--;
				UInt32 bit = (symbol >> bitIndex) & 1;
				Models[m].Encode( rangeEncoder, bit );
				m = (m << 1) | bit;
			}
		}

		public void ReverseEncode( Encoder rangeEncoder, UInt32 symbol )
		{
			UInt32 m = 1;
			for ( UInt32 i = 0; i < NumBitLevels; i++ )
			{
				UInt32 bit = symbol & 1;
				Models[m].Encode( rangeEncoder, bit );
				m = (m << 1) | bit;
				symbol >>= 1;
			}
		}

		public UInt32 GetPrice( UInt32 symbol )
		{
			UInt32 price = 0;
			UInt32 m = 1;
			for ( int bitIndex = NumBitLevels; bitIndex > 0; )
			{
				bitIndex--;
				UInt32 bit = (symbol >> bitIndex) & 1;
				price += Models[m].GetPrice( bit );
				m = (m << 1) + bit;
			}
			return price;
		}

		public UInt32 ReverseGetPrice( UInt32 symbol )
		{
			UInt32 price = 0;
			UInt32 m = 1;
			for ( int i = NumBitLevels; i > 0; i-- )
			{
				UInt32 bit = symbol & 1;
				symbol >>= 1;
				price += Models[m].GetPrice( bit );
				m = (m << 1) | bit;
			}
			return price;
		}

		public static UInt32 ReverseGetPrice( BitEncoder[] Models, UInt32 startIndex,
			int NumBitLevels, UInt32 symbol )
		{
			UInt32 price = 0;
			UInt32 m = 1;
			for ( int i = NumBitLevels; i > 0; i-- )
			{
				UInt32 bit = symbol & 1;
				symbol >>= 1;
				price += Models[startIndex + m].GetPrice( bit );
				m = (m << 1) | bit;
			}
			return price;
		}

		public static void ReverseEncode( BitEncoder[] Models, UInt32 startIndex,
			Encoder rangeEncoder, int NumBitLevels, UInt32 symbol )
		{
			UInt32 m = 1;
			for ( int i = 0; i < NumBitLevels; i++ )
			{
				UInt32 bit = symbol & 1;
				Models[startIndex + m].Encode( rangeEncoder, bit );
				m = (m << 1) | bit;
				symbol >>= 1;
			}
		}
	}

	struct BitTreeDecoder
	{
		BitDecoder[] Models;
		int NumBitLevels;

		public BitTreeDecoder( int numBitLevels )
		{
			NumBitLevels = numBitLevels;
			Models = new BitDecoder[1 << numBitLevels];
		}

		public void Init()
		{
			for ( uint i = 1; i < (1 << NumBitLevels); i++ )
				Models[i].Init();
		}

		public uint Decode( RangeCoder.Decoder rangeDecoder )
		{
			uint m = 1;
			for ( int bitIndex = NumBitLevels; bitIndex > 0; bitIndex-- )
				m = (m << 1) + Models[m].Decode( rangeDecoder );
			return m - ((uint)1 << NumBitLevels);
		}

		public uint ReverseDecode( RangeCoder.Decoder rangeDecoder )
		{
			uint m = 1;
			uint symbol = 0;
			for ( int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++ )
			{
				uint bit = Models[m].Decode( rangeDecoder );
				m <<= 1;
				m += bit;
				symbol |= (bit << bitIndex);
			}
			return symbol;
		}

		public static uint ReverseDecode( BitDecoder[] Models, UInt32 startIndex,
			RangeCoder.Decoder rangeDecoder, int NumBitLevels )
		{
			uint m = 1;
			uint symbol = 0;
			for ( int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++ )
			{
				uint bit = Models[startIndex + m].Decode( rangeDecoder );
				m <<= 1;
				m += bit;
				symbol |= (bit << bitIndex);
			}
			return symbol;
		}
	}
}