1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Buffers.Binary;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Internal.Runtime.CompilerServices;
namespace System.Buffers
{
#if !__MonoCS__
public static partial class SequenceReaderExtensions
{
/// <summary>
/// Try to read the given type out of the buffer if possible. Warning: this is dangerous to use with arbitrary
/// structs- see remarks for full details.
/// </summary>
/// <remarks>
/// IMPORTANT: The read is a straight copy of bits. If a struct depends on specific state of it's members to
/// behave correctly this can lead to exceptions, etc. If reading endian specific integers, use the explicit
/// overloads such as <see cref="TryReadLittleEndian(ref SequenceReader{byte}, out short)"/>
/// </remarks>
/// <returns>
/// True if successful. <paramref name="value"/> will be default if failed (due to lack of space).
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe bool TryRead<T>(ref this SequenceReader<byte> reader, out T value) where T : unmanaged
{
ReadOnlySpan<byte> span = reader.UnreadSpan;
if (span.Length < sizeof(T))
return TryReadMultisegment(ref reader, out value);
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(span));
reader.Advance(sizeof(T));
return true;
}
private static unsafe bool TryReadMultisegment<T>(ref SequenceReader<byte> reader, out T value) where T : unmanaged
{
Debug.Assert(reader.UnreadSpan.Length < sizeof(T));
// Not enough data in the current segment, try to peek for the data we need.
T buffer = default;
Span<byte> tempSpan = new Span<byte>(&buffer, sizeof(T));
if (!reader.TryCopyTo(tempSpan))
{
value = default;
return false;
}
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(tempSpan));
reader.Advance(sizeof(T));
return true;
}
/// <summary>
/// Reads an <see cref="short"/> as little endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="short"/>.</returns>
public static bool TryReadLittleEndian(ref this SequenceReader<byte> reader, out short value)
{
if (BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
/// <summary>
/// Reads an <see cref="short"/> as big endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="short"/>.</returns>
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out short value)
{
if (!BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
private static bool TryReadReverseEndianness(ref SequenceReader<byte> reader, out short value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
/// <summary>
/// Reads an <see cref="int"/> as little endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="int"/>.</returns>
public static bool TryReadLittleEndian(ref this SequenceReader<byte> reader, out int value)
{
if (BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
/// <summary>
/// Reads an <see cref="int"/> as big endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="int"/>.</returns>
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out int value)
{
if (!BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
private static bool TryReadReverseEndianness(ref SequenceReader<byte> reader, out int value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
/// <summary>
/// Reads an <see cref="long"/> as little endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="long"/>.</returns>
public static bool TryReadLittleEndian(ref this SequenceReader<byte> reader, out long value)
{
if (BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
/// <summary>
/// Reads an <see cref="long"/> as big endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="long"/>.</returns>
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out long value)
{
if (!BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
private static bool TryReadReverseEndianness(ref SequenceReader<byte> reader, out long value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
}
#else
public static partial class SequenceReaderExtensions
{
public static bool TryReadBigEndian(this System.Buffers.SequenceReader<byte> reader, out short value) => throw new PlatformNotSupportedException();
public static bool TryReadBigEndian(this System.Buffers.SequenceReader<byte> reader, out int value) => throw new PlatformNotSupportedException();
public static bool TryReadBigEndian(this System.Buffers.SequenceReader<byte> reader, out long value) => throw new PlatformNotSupportedException();
public static bool TryReadLittleEndian(this System.Buffers.SequenceReader<byte> reader, out short value) => throw new PlatformNotSupportedException();
public static bool TryReadLittleEndian(this System.Buffers.SequenceReader<byte> reader, out int value) => throw new PlatformNotSupportedException();
public static bool TryReadLittleEndian(this System.Buffers.SequenceReader<byte> reader, out long value) => throw new PlatformNotSupportedException();
}
#endif
}
|