private void GetAndMoveToFrontDecode()

in src/ICSharpCode.SharpZipLib/BZip2/BZip2InputStream.cs [579:770]


		private void GetAndMoveToFrontDecode()
		{
			byte[] yy = new byte[256];
			int nextSym;

			int limitLast = BZip2Constants.BaseBlockSize * blockSize100k;
			origPtr = BsGetIntVS(24);

			RecvDecodingTables();
			int EOB = nInUse + 1;
			int groupNo = -1;
			int groupPos = 0;

			/*--
			Setting up the unzftab entries here is not strictly
			necessary, but it does save having to do it later
			in a separate pass, and so saves a block's worth of
			cache misses.
			--*/
			for (int i = 0; i <= 255; i++)
			{
				unzftab[i] = 0;
			}

			for (int i = 0; i <= 255; i++)
			{
				yy[i] = (byte)i;
			}

			last = -1;

			if (groupPos == 0)
			{
				groupNo++;
				groupPos = BZip2Constants.GroupSize;
			}

			groupPos--;
			int zt = selector[groupNo];
			int zn = minLens[zt];
			int zvec = BsR(zn);
			int zj;

			while (zvec > limit[zt][zn])
			{
				if (zn > 20)
				{ // the longest code
					throw new BZip2Exception("Bzip data error");
				}
				zn++;
				while (bsLive < 1)
				{
					FillBuffer();
				}
				zj = (bsBuff >> (bsLive - 1)) & 1;
				bsLive--;
				zvec = (zvec << 1) | zj;
			}
			if (zvec - baseArray[zt][zn] < 0 || zvec - baseArray[zt][zn] >= BZip2Constants.MaximumAlphaSize)
			{
				throw new BZip2Exception("Bzip data error");
			}
			nextSym = perm[zt][zvec - baseArray[zt][zn]];

			while (true)
			{
				if (nextSym == EOB)
				{
					break;
				}

				if (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB)
				{
					int s = -1;
					int n = 1;
					do
					{
						if (nextSym == BZip2Constants.RunA)
						{
							s += (0 + 1) * n;
						}
						else if (nextSym == BZip2Constants.RunB)
						{
							s += (1 + 1) * n;
						}

						n <<= 1;

						if (groupPos == 0)
						{
							groupNo++;
							groupPos = BZip2Constants.GroupSize;
						}

						groupPos--;

						zt = selector[groupNo];
						zn = minLens[zt];
						zvec = BsR(zn);

						while (zvec > limit[zt][zn])
						{
							zn++;
							while (bsLive < 1)
							{
								FillBuffer();
							}
							zj = (bsBuff >> (bsLive - 1)) & 1;
							bsLive--;
							zvec = (zvec << 1) | zj;
						}
						nextSym = perm[zt][zvec - baseArray[zt][zn]];
					} while (nextSym == BZip2Constants.RunA || nextSym == BZip2Constants.RunB);

					s++;
					byte ch = seqToUnseq[yy[0]];
					unzftab[ch] += s;

					while (s > 0)
					{
						last++;
						ll8[last] = ch;
						s--;
					}

					if (last >= limitLast)
					{
						BlockOverrun();
					}
					continue;
				}
				else
				{
					last++;
					if (last >= limitLast)
					{
						BlockOverrun();
					}

					byte tmp = yy[nextSym - 1];
					unzftab[seqToUnseq[tmp]]++;
					ll8[last] = seqToUnseq[tmp];

					var j = nextSym - 1;

#if VECTORIZE_MEMORY_MOVE
					// This is vectorized memory move. Going from the back, we're taking chunks of array
					// and write them at the new location shifted by one. Since chunks are VectorSize long,
					// at the end we have to move "tail" (or head actually) of the array using a plain loop.
					// If System.Numerics.Vector API is not available, the plain loop is used to do the whole copying.

					while(j >= VectorSize)
					{
						var arrayPart = new System.Numerics.Vector<byte>(yy, j - VectorSize);
						arrayPart.CopyTo(yy, j - VectorSize + 1);
						j -= VectorSize;
					}
#endif // VECTORIZE_MEMORY_MOVE

					while(j > 0)
					{
						yy[j] = yy[--j];
					}

					yy[0] = tmp;

					if (groupPos == 0)
					{
						groupNo++;
						groupPos = BZip2Constants.GroupSize;
					}

					groupPos--;
					zt = selector[groupNo];
					zn = minLens[zt];
					zvec = BsR(zn);
					while (zvec > limit[zt][zn])
					{
						zn++;
						while (bsLive < 1)
						{
							FillBuffer();
						}
						zj = (bsBuff >> (bsLive - 1)) & 1;
						bsLive--;
						zvec = (zvec << 1) | zj;
					}
					nextSym = perm[zt][zvec - baseArray[zt][zn]];
					continue;
				}
			}
		}