public static byte[] Decode(byte[] encodedData, ConcurrentDictionary <BitsWithLength, byte> decodeTable,
                                    long bitsCount, int degreeOfParallelism)
        {
            var result = new List <byte>();

            var sample = new BitsWithLength {
                Bits = 0, BitsCount = 0
            };

            for (var byteNum = 0; byteNum < encodedData.Length; byteNum++)
            {
                var b = encodedData[byteNum];
                for (var bitNum = 0; bitNum < 8 && byteNum * 8 + bitNum < bitsCount; bitNum++)
                {
                    sample.Bits = (sample.Bits << 1) + ((b & (1 << (8 - bitNum - 1))) != 0 ? 1 : 0);
                    sample.BitsCount++;

                    byte decodedByte;
                    if (decodeTable.TryGetValue(sample, out decodedByte))
                    {
                        result.Add(decodedByte);

                        sample.BitsCount = 0;
                        sample.Bits      = 0;
                    }
                }
            }
            return(result.ToArray());
        }
        public static byte[] Encode(byte[] data, out ConcurrentDictionary <BitsWithLength, byte> decodeTable,
                                    out long bitsCount, int degreeOfParallelism)
        {
            var frequences = CalcFrequences(data, degreeOfParallelism);

            var root = BuildHuffmanTree(frequences);

            var encodeTable = new BitsWithLength[byte.MaxValue + 1];

            FillEncodeTable(root, encodeTable);

            var dataSize    = data.Length;
            var chunkLength = dataSize / degreeOfParallelism;

            ParallelEnumerable.Range(0, degreeOfParallelism + 1)
            .AsOrdered()
            .WithDegreeOfParallelism(degreeOfParallelism)
            .Select(
                i =>
            {
                var chunk = new BitsBuffer();
                var lower = chunkLength * i;
                var upper = Math.Min(chunkLength * (i + 1), dataSize);
                for (var j = lower; j < upper; j++)
                {
                    chunk.Add(encodeTable[data[j]]);
                }
                return(chunk);
            })
            .ForEach(AddRange);
            decodeTable = CreateDecodeTable(encodeTable, degreeOfParallelism);

            return(globalBuffer.ToArray(out bitsCount));
        }
        public void Add(BitsWithLength bitsWithLength, int bitsCount = 0)
        {
            if (bitsCount == 0)
            {
                bitsCount = bitsWithLength.BitsCount;
            }
            var bits = bitsWithLength.Bits;

            var neededBits = 8 - unfinishedBits.BitsCount;

            while (bitsCount >= neededBits)
            {
                bitsCount -= neededBits;
                buffer.Add((byte)((unfinishedBits.Bits << neededBits) + (bits >> bitsCount)));

                bits = bits & ((1 << bitsCount) - 1);

                unfinishedBits.Bits      = 0;
                unfinishedBits.BitsCount = 0;

                neededBits = 8;
            }
            unfinishedBits.BitsCount += bitsCount;
            unfinishedBits.Bits       = (unfinishedBits.Bits << bitsCount) + bits;
        }
        public static byte[] EncodeSequential(byte[] data, out ConcurrentDictionary <BitsWithLength, byte> decodeTable,
                                              out long bitsCount, int degreeOfParallelism)
        {
            var frequences = CalcFrequences(data, degreeOfParallelism);

            var root = BuildHuffmanTree(frequences);

            var encodeTable = new BitsWithLength[byte.MaxValue + 1];

            FillEncodeTable(root, encodeTable);

            var bitsBuffer = new BitsBuffer();

            foreach (var b in data)
            {
                bitsBuffer.Add(encodeTable[b]);
            }

            decodeTable = CreateDecodeTable(encodeTable, degreeOfParallelism);

            return(bitsBuffer.ToArray(out bitsCount));
        }