in Microsoft.Azure.Cosmos/src/Json/JsonWriter.JsonBinaryWriter.cs [1019:1197]
static private bool TryWriteUniformNumberArray(
JsonBinaryMemoryWriter arrayWriter,
int byteCount,
int valueLength,
int itemCount)
{
if (arrayWriter == null) throw new ArgumentNullException(nameof(arrayWriter));
if (byteCount <= 0) throw new ArgumentException($"Value must be greater than 0.", nameof(byteCount));
if (valueLength <= 0) throw new ArgumentException($"Value must be greater than 0.", nameof(valueLength));
// Uniform arrays only support 1 and 2-byte item count
if (itemCount > ushort.MaxValue) return false;
int floatCount = 0;
long maxValue = long.MinValue;
long minValue = long.MaxValue;
List<Number64> numberValues = new List<Number64>(itemCount);
ReadOnlySpan<byte> arrayBuffer = arrayWriter.BufferAsSpan.Slice(arrayWriter.Position + byteCount, valueLength);
while (!arrayBuffer.IsEmpty)
{
if (!TypeMarker.IsNumber(arrayBuffer[0]))
{
// We encountered a non-number value, so we bail out
return false;
}
if (JsonBinaryEncoding.TryGetNumberValue(
arrayBuffer,
uniformArrayInfo: null,
out Number64 value,
out int itemLength))
{
numberValues.Add(value);
if (value.IsInteger)
{
maxValue = Math.Max(maxValue, Number64.ToLong(value));
minValue = Math.Min(minValue, Number64.ToLong(value));
}
else
{
floatCount++;
}
}
else
{
throw new JsonUnexpectedTokenException();
}
arrayBuffer = arrayBuffer.Slice(itemLength);
}
// Assert(numberValues.Count == itemCount);
// Assert(itemCount >= floatCount);
byte itemTypeMarker;
int itemSize;
if (floatCount > 0)
{
if (floatCount < itemCount)
{
// Not all items are floating-point values, we need to check for integer values that
// cannot be represented as floating-point values without losing precision.
long nMaxAbsValue = Math.Max(Math.Abs(minValue), Math.Abs(maxValue));
if (nMaxAbsValue > (1L << 53)) return false;
}
itemTypeMarker = TypeMarker.Float64;
itemSize = sizeof(double);
}
else
{
if ((minValue >= 0) && (maxValue <= byte.MaxValue))
{
itemTypeMarker = TypeMarker.UInt8;
itemSize = sizeof(byte);
}
else if ((minValue >= sbyte.MinValue) && (maxValue <= sbyte.MaxValue))
{
itemTypeMarker = TypeMarker.Int8;
itemSize = sizeof(sbyte);
}
else if ((minValue >= short.MinValue) && (maxValue <= short.MaxValue))
{
itemTypeMarker = TypeMarker.Int16;
itemSize = sizeof(short);
}
else if ((minValue >= int.MinValue) && (maxValue <= int.MaxValue))
{
itemTypeMarker = TypeMarker.Int32;
itemSize = sizeof(int);
}
else
{
itemTypeMarker = TypeMarker.Int64;
itemSize = sizeof(long);
}
}
int newByteCount = 1 /* item TypeMarker */ + (itemCount <= byte.MaxValue ? 1 : 2) /* item count */;
int newLength = 1 + newByteCount + (itemCount * itemSize);
int oldLength = 1 + byteCount + valueLength;
// Verify whether writing a uniform number array is beneficial
if (newLength > oldLength)
{
return false;
}
if (itemCount <= byte.MaxValue)
{
arrayWriter.Write(TypeMarker.ArrNumC1);
arrayWriter.Write(itemTypeMarker);
arrayWriter.Write((byte)itemCount);
}
else
{
arrayWriter.Write(TypeMarker.ArrNumC2);
arrayWriter.Write(itemTypeMarker);
arrayWriter.Write((short)itemCount);
}
// Write the uniform number array beginning at the start offset
switch (itemTypeMarker)
{
case TypeMarker.Int8:
foreach (Number64 value in numberValues)
{
arrayWriter.Write((sbyte)Number64.ToLong(value));
}
break;
case TypeMarker.UInt8:
foreach (Number64 value in numberValues)
{
arrayWriter.Write((byte)Number64.ToLong(value));
}
break;
case TypeMarker.Int16:
foreach (Number64 value in numberValues)
{
arrayWriter.Write((short)Number64.ToLong(value));
}
break;
case TypeMarker.Int32:
foreach (Number64 value in numberValues)
{
arrayWriter.Write((int)Number64.ToLong(value));
}
break;
case TypeMarker.Int64:
foreach (Number64 value in numberValues)
{
arrayWriter.Write(Number64.ToLong(value));
}
break;
case TypeMarker.Float16:
// Currently not supported
throw new InvalidOperationException();
case TypeMarker.Float32:
foreach (Number64 value in numberValues)
{
arrayWriter.Write((float)Number64.ToDouble(value));
}
break;
case TypeMarker.Float64:
foreach (Number64 value in numberValues)
{
arrayWriter.Write(Number64.ToDouble(value));
}
break;
default:
throw new InvalidOperationException();
}
return true;
}