long(Int64)をUtf8に変換する(後編)

前編では、Utf8JsonのWriteInt64を少し改造しました。
これは、byte[]に書き出す仕様のため、新しくbyte[]を作る場合を作ってみる。

方法として、Spanをstackallocで確保して、そこに書き込みんでおき、最後にbyte[]化するか、長さが確定したときに、byte[]を作成する方法の2つが考えられた。
計測してみたところ、byte[]に直接書く方が速かった。
やはり、Span→byte[]にコピーする分、遅くなっているのでしょうね。

| SpanToArray_Bench | 6.224 us | 0.0611 us | 0.0511 us |
| DirectArray_Bench | 5.347 us | 0.0444 us | 0.0394 us |

一応、両方のコードを下に載せておきます。

public static byte[] GetBytesFromInt64_SpanToArray(long value)
{
    Span<byte> buffer = stackalloc byte[21];

    int offset = 0;
    uint num1, num2, num3, num4, num5, div;
    ulong valueA, valueB;

    if (value < 0)
    {
        if (value == long.MinValue)
        {
            ReadOnlySpan<byte> minValue = "-9223372036854775808"u8;
            return minValue.ToArray();
        }

        buffer[offset++] = (byte)'-';
        valueA = (ulong)(unchecked(-value));
    }
    else
    {
        valueA = (ulong)value;
    }

    if (valueA < 10000)
    {
        num1 = (uint)valueA;
        if (num1 < 10) { goto L1; }
        if (num1 < 100) { goto L2; }
        if (num1 < 1000) { goto L3; }
        goto L4;
    }
    else
    {
        valueB = valueA / 10000;
        num1 = (uint)(valueA - valueB * 10000);
        if (valueB < 10000)
        {
            num2 = (uint)valueB;
            if (num2 < 100)
            {
                if (num2 < 10) { goto L5; }
                goto L6;
            }
            if (num2 < 1000) { goto L7; }
            goto L8;
        }
        else
        {
            valueA = valueB / 10000;
            num2 = (uint)(valueB - valueA * 10000);
            if (valueA < 10000)
            {
                num3 = (uint)valueA;
                if (num3 < 100)
                {
                    if (num3 < 10) { goto L9; }
                    goto L10;
                }
                if (num3 < 1000) { goto L11; }
                goto L12;
            }
            else
            {
                valueB = valueA / 10000;
                num3 = (uint)(valueA - valueB * 10000);
                if (valueB < 10000)
                {
                    num4 = (uint)valueB;
                    if (num4 < 100)
                    {
                        if (num4 < 10) { goto L13; }
                        goto L14;
                    }
                    if (num4 < 1000) { goto L15; }
                    goto L16;
                }
                else
                {
                    valueA = valueB / 10000;
                    num4 = (uint)(valueB - valueA * 10000);
                    //if (value2 < 10000)
                    {
                        num5 = (uint)valueA;
                        if (num5 < 100)
                        {
                            if (num5 < 10) { goto L17; }
                            goto L18;
                        }
                        if (num5 < 1000) { goto L19; }
                        goto L20;
                    }
                L20:
                    buffer[offset++] = (byte)('0' + (div = (num5 * 8389) >> 23));
                    num5 -= div * 1000;
                L19:
                    buffer[offset++] = (byte)('0' + (div = (num5 * 5243) >> 19));
                    num5 -= div * 100;
                L18:
                    buffer[offset++] = (byte)('0' + (div = (num5 * 6554) >> 16));
                    num5 -= div * 10;
                L17:
                    buffer[offset++] = (byte)('0' + (num5));
                }
            L16:
                buffer[offset++] = (byte)('0' + (div = (num4 * 8389) >> 23));
                num4 -= div * 1000;
            L15:
                buffer[offset++] = (byte)('0' + (div = (num4 * 5243) >> 19));
                num4 -= div * 100;
            L14:
                buffer[offset++] = (byte)('0' + (div = (num4 * 6554) >> 16));
                num4 -= div * 10;
            L13:
                buffer[offset++] = (byte)('0' + (num4));
            }
        L12:
            buffer[offset++] = (byte)('0' + (div = (num3 * 8389) >> 23));
            num3 -= div * 1000;
        L11:
            buffer[offset++] = (byte)('0' + (div = (num3 * 5243) >> 19));
            num3 -= div * 100;
        L10:
            buffer[offset++] = (byte)('0' + (div = (num3 * 6554) >> 16));
            num3 -= div * 10;
        L9:
            buffer[offset++] = (byte)('0' + (num3));
        }
    L8:
        buffer[offset++] = (byte)('0' + (div = (num2 * 8389) >> 23));
        num2 -= div * 1000;
    L7:
        buffer[offset++] = (byte)('0' + (div = (num2 * 5243) >> 19));
        num2 -= div * 100;
    L6:
        buffer[offset++] = (byte)('0' + (div = (num2 * 6554) >> 16));
        num2 -= div * 10;
    L5:
        buffer[offset++] = (byte)('0' + (num2));
    }
L4:
    buffer[offset++] = (byte)('0' + (div = (num1 * 8389) >> 23));
    num1 -= div * 1000;
L3:
    buffer[offset++] = (byte)('0' + (div = (num1 * 5243) >> 19));
    num1 -= div * 100;
L2:
    buffer[offset++] = (byte)('0' + (div = (num1 * 6554) >> 16));
    num1 -= div * 10;
L1:
    buffer[offset++] = (byte)('0' + (num1));

    return buffer[..offset].ToArray();
}

public static byte[] GetBytesFromInt64_DirectArray(long value)
{
    int minusAdd = 0;
    byte[] buffer;

    int offset = 0;
    uint num1, num2, num3, num4, num5, div;
    ulong valueA, valueB;

    if (value < 0)
    {
        if (value == long.MinValue)
        {
            ReadOnlySpan<byte> minValue = "-9223372036854775808"u8;
            return minValue.ToArray();
        }

        minusAdd = 1;
        offset = 1;
        valueA = (ulong)(unchecked(-value));
    }
    else
    {
        valueA = (ulong)value;
    }

    if (valueA < 10000)
    {
        num1 = (uint)valueA;
        if (num1 < 10) { buffer = new byte[minusAdd + 1]; goto L1; }
        if (num1 < 100) { buffer = new byte[minusAdd + 2]; goto L2; }
        if (num1 < 1000) { buffer = new byte[minusAdd + 3]; goto L3; }
        buffer = new byte[minusAdd + 4]; goto L4;
    }
    else
    {
        valueB = valueA / 10000;
        num1 = (uint)(valueA - valueB * 10000);
        if (valueB < 10000)
        {
            num2 = (uint)valueB;
            if (num2 < 100)
            {
                if (num2 < 10) { buffer = new byte[minusAdd + 5]; goto L5; }
                buffer = new byte[minusAdd + 6]; goto L6;
            }
            if (num2 < 1000) { buffer = new byte[minusAdd + 7]; goto L7; }
            buffer = new byte[minusAdd + 8]; goto L8;
        }
        else
        {
            valueA = valueB / 10000;
            num2 = (uint)(valueB - valueA * 10000);
            if (valueA < 10000)
            {
                num3 = (uint)valueA;
                if (num3 < 100)
                {
                    if (num3 < 10) { buffer = new byte[minusAdd + 9]; goto L9; }
                    buffer = new byte[minusAdd + 10]; goto L10;
                }
                if (num3 < 1000) { buffer = new byte[minusAdd + 11]; goto L11; }
                buffer = new byte[minusAdd + 12]; goto L12;
            }
            else
            {
                valueB = valueA / 10000;
                num3 = (uint)(valueA - valueB * 10000);
                if (valueB < 10000)
                {
                    num4 = (uint)valueB;
                    if (num4 < 100)
                    {
                        if (num4 < 10) { buffer = new byte[minusAdd + 13]; goto L13; }
                        buffer = new byte[minusAdd + 14]; goto L14;
                    }
                    if (num4 < 1000) { buffer = new byte[minusAdd + 15]; goto L15; }
                    buffer = new byte[minusAdd + 16]; goto L16;
                }
                else
                {
                    valueA = valueB / 10000;
                    num4 = (uint)(valueB - valueA * 10000);
                    //if (value2 < 10000)
                    {
                        num5 = (uint)valueA;
                        if (num5 < 100)
                        {
                            if (num5 < 10) { buffer = new byte[minusAdd + 17]; goto L17; }
                            buffer = new byte[minusAdd + 18]; goto L18;
                        }
                        if (num5 < 1000) { buffer = new byte[minusAdd + 19]; goto L19; }
                        buffer = new byte[minusAdd + 20]; goto L20;
                    }
                L20:
                    buffer[offset++] = (byte)('0' + (div = (num5 * 8389) >> 23));
                    num5 -= div * 1000;
                L19:
                    buffer[offset++] = (byte)('0' + (div = (num5 * 5243) >> 19));
                    num5 -= div * 100;
                L18:
                    buffer[offset++] = (byte)('0' + (div = (num5 * 6554) >> 16));
                    num5 -= div * 10;
                L17:
                    buffer[offset++] = (byte)('0' + (num5));
                }
            L16:
                buffer[offset++] = (byte)('0' + (div = (num4 * 8389) >> 23));
                num4 -= div * 1000;
            L15:
                buffer[offset++] = (byte)('0' + (div = (num4 * 5243) >> 19));
                num4 -= div * 100;
            L14:
                buffer[offset++] = (byte)('0' + (div = (num4 * 6554) >> 16));
                num4 -= div * 10;
            L13:
                buffer[offset++] = (byte)('0' + (num4));
            }
        L12:
            buffer[offset++] = (byte)('0' + (div = (num3 * 8389) >> 23));
            num3 -= div * 1000;
        L11:
            buffer[offset++] = (byte)('0' + (div = (num3 * 5243) >> 19));
            num3 -= div * 100;
        L10:
            buffer[offset++] = (byte)('0' + (div = (num3 * 6554) >> 16));
            num3 -= div * 10;
        L9:
            buffer[offset++] = (byte)('0' + (num3));
        }
    L8:
        buffer[offset++] = (byte)('0' + (div = (num2 * 8389) >> 23));
        num2 -= div * 1000;
    L7:
        buffer[offset++] = (byte)('0' + (div = (num2 * 5243) >> 19));
        num2 -= div * 100;
    L6:
        buffer[offset++] = (byte)('0' + (div = (num2 * 6554) >> 16));
        num2 -= div * 10;
    L5:
        buffer[offset++] = (byte)('0' + (num2));
    }
L4:
    buffer[offset++] = (byte)('0' + (div = (num1 * 8389) >> 23));
    num1 -= div * 1000;
L3:
    buffer[offset++] = (byte)('0' + (div = (num1 * 5243) >> 19));
    num1 -= div * 100;
L2:
    buffer[offset++] = (byte)('0' + (div = (num1 * 6554) >> 16));
    num1 -= div * 10;
L1:
    buffer[offset++] = (byte)('0' + (num1));

    if(minusAdd != 0) { buffer[0] = (byte)'-'; }
    return buffer;
}
投稿日:
カテゴリー: C#

1件のコメント

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です