/// <summary>
        /// Deserializes to an array of nullable <see lang="double"/> from the specified reader.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <returns>An array of nullable <see lang="double"/>.</returns>
        public static double?[] DeserializeToNullableDoubles(BinaryReader reader)
        {
            // version not in use yet.
            reader.ReadByte();
            var numOfItems = (int)SerializationUtils.ReadUInt32FromBase128(reader);

            if (numOfItems == 0)
            {
                return(EmptyNullableDoubleArray);
            }

            var result = new double?[numOfItems];

            var bitBinaryReader = new BitBinaryReader(reader);
            var previousState   = new DoubleValueState(0, -1, -1);

            for (int i = 0; i < numOfItems; ++i)
            {
                var newState = ReadDouble(bitBinaryReader, previousState);
                result[i]     = double.IsNaN(newState.Value) ? (double?)null : newState.Value;
                previousState = newState;
            }

            return(result);
        }
        private static bool WriteDouble(BitBinaryWriter writer, double value, DoubleValueState previousValue, out DoubleValueState newValue)
        {
            newValue       = previousValue;
            newValue.Value = value;

            var xor = BitConverter.DoubleToInt64Bits(value) ^ BitConverter.DoubleToInt64Bits(previousValue.Value);

            if (xor == 0)
            {
                writer.WriteBit(false);
            }
            else
            {
                writer.WriteBit(true);

                var leadingZeros  = (sbyte)BitAggregateMagic.CountLeadingZeros(xor);
                var trailingZeros = (sbyte)BitAggregateMagic.CountTrailingZeros(xor);

                if (leadingZeros > MaxLeadingZerosLength)
                {
                    leadingZeros = MaxLeadingZerosLength;
                }

                int blockSize    = 64 - leadingZeros - trailingZeros;
                int expectedSize = NumBitsToEncodeNumLeadingZeros + NumBitsToEncodeNumMeaningfulBits + blockSize;
                int previousBlockInformationSize = 64 - previousValue.TrailingZeros - previousValue.LeadingZeros;

                // The block position is set by the first non-zero XOR value. previousValue.LeadingZeros was initialized to -1s to start with.
                if (previousValue.LeadingZeros > 0 && leadingZeros >= previousValue.LeadingZeros && trailingZeros >= previousValue.TrailingZeros && previousBlockInformationSize < expectedSize)
                {
                    writer.WriteBit(false);

                    // there are at least as many leading zeros and as many trailing zeros as with the previous value, reuse the block position.
                    var numMeaningfulBits = BitAggregateMagic.NumBitsInLongInteger - previousValue.LeadingZeros - previousValue.TrailingZeros;

                    writer.WriteBits(xor, numMeaningfulBits, previousValue.TrailingZeros);
                }
                else
                {
                    // start a new block position
                    writer.WriteBit(true);

                    writer.WriteBits(leadingZeros, NumBitsToEncodeNumLeadingZeros, 0);

                    newValue.LeadingZeros = leadingZeros;

                    var numMeaningfulBits = BitAggregateMagic.NumBitsInLongInteger - leadingZeros - trailingZeros;
                    writer.WriteBits(numMeaningfulBits, NumBitsToEncodeNumMeaningfulBits, 0);

                    newValue.TrailingZeros = trailingZeros;

                    writer.WriteBits(xor, numMeaningfulBits, trailingZeros);
                }
            }

            return(true);
        }
        private static unsafe void DeserializeValues(BinaryReader reader, double *values, int count)
        {
            var bitBinaryReader = new BitBinaryReader(reader);
            var previousState   = new DoubleValueState(0, -1, -1);

            for (int i = 0; i < count; ++i)
            {
                var newState = ReadDouble(bitBinaryReader, previousState);
                values[i]     = newState.Value;
                previousState = newState;
            }
        }
        public static unsafe void Serialize(BinaryWriter writer, double *values, int count)
        {
            // Reserve one byte for future versioning.
            writer.Write((byte)1);
            SerializationUtils.WriteUInt32AsBase128(writer, (uint)count);
            if (count > 0)
            {
                BitBinaryWriter bitWriter     = new BitBinaryWriter(writer);
                var             previousState = new DoubleValueState(0, -1, -1);

                for (int i = 0; i < count; ++i)
                {
                    DoubleValueState newState;
                    WriteDouble(bitWriter, values[i], previousState, out newState);
                    previousState = newState;
                }

                bitWriter.Flush();
            }
        }
        private static DoubleValueState ReadDouble(BitBinaryReader reader, DoubleValueState state)
        {
            var firstBit = reader.ReadBit();

            if (!firstBit)
            {
                return(state);
            }

            var  secondBit = reader.ReadBit();
            long meaningFulBits;

            if (!secondBit)
            {
                var numBitsToRead = BitAggregateMagic.NumBitsInLongInteger - state.LeadingZeros - state.TrailingZeros;
                meaningFulBits = reader.ReadBits(numBitsToRead);
            }
            else
            {
                // a new block position was started since the number starts with "11".
                state.LeadingZeros = (sbyte)reader.ReadBits(NumBitsToEncodeNumLeadingZeros);
                var numBitsToRead = (sbyte)reader.ReadBits(NumBitsToEncodeNumMeaningfulBits);
                if (numBitsToRead == 0)
                {
                    // The block size is 64 bits which becomes 0 in writing into 6 bits - overflow.
                    // If the block size were indeed 0 bits, the xor value would be 0, and the actual value would be identical to the prior value,
                    // so we would have bailed out early on since firstBit would be 0.
                    numBitsToRead = (sbyte)BitAggregateMagic.NumBitsInLongInteger;
                }

                state.TrailingZeros = (sbyte)(BitAggregateMagic.NumBitsInLongInteger - state.LeadingZeros - numBitsToRead);
                meaningFulBits      = reader.ReadBits(numBitsToRead);
            }

            var xor = meaningFulBits << state.TrailingZeros;

            state.Value = BitConverter.Int64BitsToDouble(xor ^ BitConverter.DoubleToInt64Bits(state.Value));
            return(state);
        }