|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
namespace System.Net.Http.HPack
{
internal static class IntegerEncoder
{
/// <summary>
/// The maximum bytes required to encode a 32-bit int, regardless of prefix length.
/// </summary>
public const int MaxInt32EncodedLength = 6;
/// <summary>
/// Encodes an integer into one or more bytes.
/// </summary>
/// <param name="value">The value to encode. Must not be negative.</param>
/// <param name="numBits">The length of the prefix, in bits, to encode <paramref name="value"/> within. Must be between 1 and 8.</param>
/// <param name="destination">The destination span to encode <paramref name="value"/> to.</param>
/// <param name="bytesWritten">The number of bytes used to encode <paramref name="value"/>.</param>
/// <returns>If <paramref name="destination"/> had enough storage to encode <paramref name="value"/>, true. Otherwise, false.</returns>
public static bool Encode(int value, int numBits, Span<byte> destination, out int bytesWritten)
{
Debug.Assert(value >= 0);
Debug.Assert(numBits >= 1 && numBits <= 8);
if (destination.Length == 0)
{
bytesWritten = 0;
return false;
}
destination[0] &= MaskHigh(8 - numBits);
if (value < (1 << numBits) - 1)
{
destination[0] |= (byte)value;
bytesWritten = 1;
return true;
}
else
{
destination[0] |= (byte)((1 << numBits) - 1);
if (1 == destination.Length)
{
bytesWritten = 0;
return false;
}
value -= ((1 << numBits) - 1);
int i = 1;
while (value >= 128)
{
destination[i++] = (byte)(value % 128 + 128);
if (i >= destination.Length)
{
bytesWritten = 0;
return false;
}
value /= 128;
}
destination[i++] = (byte)value;
bytesWritten = i;
return true;
}
}
private static byte MaskHigh(int n) => (byte)(sbyte.MinValue >> (n - 1));
}
}
|