コード例 #1
0
ファイル: BatchDouble.cs プロジェクト: xhydongda/Easydata
        // FloatArrayEncodeAll encodes src into b, returning b and any error encountered.
        // The returned slice may be of a different length and capactity to b.
        //
        // Currently only the float compression scheme used in Facebook's Gorilla is
        // supported, so this method implements a batch oriented version of that.
        public (ByteWriter, string) EncodingAll(Span <double> src)
        {
            int length = src.Length;
            //9=Enough room for the header and one value.
            ByteWriter result = new ByteWriter(length * 10 + 9);

            byte[]      bytes = result.EndWrite();
            Span <byte> b     = new Span <byte>(bytes);

            b.Fill(0);
            b[0] = (floatCompressedGorilla << 4);
            double first;
            bool   finished = false;

            if (length > 0 && Double.IsNaN(src[0]))
            {
                result.Release();
                return(null, "unsupported value: NaN");
            }
            else if (length == 0)
            {
                first    = Double.NaN;// Write sentinal value to terminate batch.
                finished = true;
            }
            else
            {
                first = src[0];
                src   = src.Slice(1);
            }

            int   n    = 8 + 64;//Number of bits written.
            ulong prev = Float64bits(first);

            // Write first value.
            ByteWriter.WriteBigEndian(bytes, 1, prev);

            int    prevLeading = -1, prevTrailing = 0;
            int    leading, trailing;
            ulong  mask;
            double sum = 0;

            // Encode remaining values.
            for (int i = 0; !finished; i++)
            {
                double x;
                if (i < src.Length)
                {
                    x    = src[i];
                    sum += x;
                }
                else
                {
                    // Encode sentinal value to terminate batch
                    x        = double.NaN;
                    finished = true;
                }
                ulong cur    = Float64bits(x);
                ulong vDelta = cur ^ prev;
                if (vDelta == 0)
                {
                    n++;// Write a zero bit. Nothing else to do.
                    prev = cur;
                    continue;
                }
                // n&7 - current bit in current byte.
                // n>>3 - the current byte.
                b[n >> 3] |= (byte)(128 >> (n & 7));// Sets the current bit of the current byte.
                n++;
                // Write the delta to b.
                // Determine the leading and trailing zeros.
                leading  = Encoding.Clz(vDelta);
                trailing = Encoding.Ctz(vDelta);
                // Clamp number of leading zeros to avoid overflow when encoding
                leading &= 0x1F;
                if (leading >= 32)
                {
                    leading = 31;
                }
                if (prevLeading != -1 && leading >= prevLeading && trailing >= prevTrailing)
                {
                    n++;// Write a zero bit.
                    // Write the l least significant bits of vDelta to b, most significant
                    // bit first.
                    int L = 64 - prevLeading - prevTrailing;
                    // Full value to write.
                    ulong v       = (vDelta >> prevTrailing) << (64 - L); // l least signifciant bits of v.
                    int   m       = n & 7;                                // Current bit in current byte.
                    int   written = 0;
                    if (m > 0)                                            // In this case the current byte is not full.
                    {
                        written = 8 - m;
                        if (L < written)
                        {
                            written = L;
                        }
                        mask       = v >> 56;// Move 8 MSB to 8 LSB
                        b[n >> 3] |= (byte)(mask >> m);
                        n         += written;
                        if (L == written)
                        {
                            prev = cur;
                            continue;
                        }
                    }
                    var vv = v << written;// Move written bits out of the way.
                    ByteWriter.WriteBigEndian(bytes, n >> 3, vv);
                    n += (L - written);
                }
                else
                {
                    prevLeading  = leading;
                    prevTrailing = trailing;
                    // Set a single bit to indicate a value will follow.
                    b[n >> 3] |= (byte)(128 >> (n & 7));// Set current bit on current byte
                    n++;
                    int   m = n & 7;
                    int   L = 5;
                    ulong v = (ulong)leading << 59; // 5 LSB of leading.
                    mask = v >> 56;                 // Move 5 MSB to 8 LSB
                    if (m <= 3)                     // 5 bits fit into current byte.
                    {
                        b[n >> 3] |= (byte)(mask >> m);
                        n          = n + L;
                    }
                    else// In this case there are fewer than 5 bits available in current byte.
                    {
                        // First step is to fill current byte
                        int written = 8 - m;
                        b[n >> 3] |= (byte)(mask >> m);// Some of mask will get lost.
                        n         += written;
                        // Second step is to write the lost part of mask into the next byte.
                        mask       = v << written; // Move written bits in previous byte out of way.
                        mask     >>= 56;
                        m          = n & 7;        //Recompute current bit.
                        b[n >> 3] |= (byte)(mask >> m);
                        n         += (L - written);
                    }
                    // Note that if leading == trailing == 0, then sigbits == 64.  But that
                    // value doesn't actually fit into the 6 bits we have.
                    // Luckily, we never need to encode 0 significant bits, since that would
                    // put us in the other case (vdelta == 0).  So instead we write out a 0 and
                    // adjust it back to 64 on unpacking.
                    int sigbits = 64 - leading - trailing;
                    m    = n & 7;
                    L    = 6;
                    v    = (ulong)sigbits << 58; // Move 6 LSB of sigbits to MSB
                    mask = v >> 56;              // Move 6 MSB to 8 LSB
                    if (m <= 2)
                    {
                        // The 6 bits fit into the current byte.
                        b[n >> 3] |= (byte)(mask >> m);
                        n         += L;
                    }
                    else// In this case there are fewer than 6 bits available in current byte.
                    {
                        // First step is to fill the current byte.
                        int written = 8 - m;
                        b[n >> 3] |= (byte)(mask >> m);// Write to the current bit.
                        n         += written;

                        // Second step is to write the lost part of mask into the next byte.
                        // Write l remaining bits into current byte.
                        mask       = v << written; // Remove bits written in previous byte out of way.
                        mask     >>= 56;
                        m          = n & 7;        // Recompute current bit.
                        b[n >> 3] |= (byte)(mask >> m);
                        n         += L - written;
                    }
                    // Write final value.
                    m = n & 7;
                    L = sigbits;
                    v = (vDelta >> trailing) << (64 - L); // Move l LSB into MSB
                    int written2 = 0;
                    if (m > 0)                            // In this case the current byte is not full.
                    {
                        written2 = 8 - m;
                        if (L < written2)
                        {
                            written2 = L;
                        }
                        mask       = v >> 56;//Move 8 MSB to 8 LSB
                        b[n >> 3] |= (byte)(mask >> m);
                        n         += written2;
                        if (L - written2 == 0)
                        {
                            prev = cur;
                            continue;
                        }
                    }
                    // Shift remaining bits and write out in one go.
                    ulong vv = v << written2;// Remove bits written in previous byte.
                    ByteWriter.WriteBigEndian(bytes, n >> 3, vv);
                    n += (L - written2);
                }
                prev = cur;
            }
            if (Double.IsNaN(sum))
            {
                result.Release();
                return(null, "unsupported value: NaN");
            }
            int blength = n >> 3;

            if ((n & 7) > 0)
            {
                blength++; // Add an extra byte to capture overflowing bits.
            }
            result.Length = blength;
            return(result, null);
        }