1*890232f2SAndroid Build Coastguard Worker /* 2*890232f2SAndroid Build Coastguard Worker * Copyright 2014 Google Inc. All rights reserved. 3*890232f2SAndroid Build Coastguard Worker * 4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*890232f2SAndroid Build Coastguard Worker * 8*890232f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*890232f2SAndroid Build Coastguard Worker * 10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*890232f2SAndroid Build Coastguard Worker * limitations under the License. 15*890232f2SAndroid Build Coastguard Worker */ 16*890232f2SAndroid Build Coastguard Worker 17*890232f2SAndroid Build Coastguard Worker // There are three conditional compilation symbols that have an impact on performance/features of this ByteBuffer implementation. 18*890232f2SAndroid Build Coastguard Worker // 19*890232f2SAndroid Build Coastguard Worker // UNSAFE_BYTEBUFFER 20*890232f2SAndroid Build Coastguard Worker // This will use unsafe code to manipulate the underlying byte array. This 21*890232f2SAndroid Build Coastguard Worker // can yield a reasonable performance increase. 22*890232f2SAndroid Build Coastguard Worker // 23*890232f2SAndroid Build Coastguard Worker // BYTEBUFFER_NO_BOUNDS_CHECK 24*890232f2SAndroid Build Coastguard Worker // This will disable the bounds check asserts to the byte array. This can 25*890232f2SAndroid Build Coastguard Worker // yield a small performance gain in normal code. 26*890232f2SAndroid Build Coastguard Worker // 27*890232f2SAndroid Build Coastguard Worker // ENABLE_SPAN_T 28*890232f2SAndroid Build Coastguard Worker // This will enable reading and writing blocks of memory with a Span<T> instead of just 29*890232f2SAndroid Build Coastguard Worker // T[]. You can also enable writing directly to shared memory or other types of memory 30*890232f2SAndroid Build Coastguard Worker // by providing a custom implementation of ByteBufferAllocator. 31*890232f2SAndroid Build Coastguard Worker // ENABLE_SPAN_T also requires UNSAFE_BYTEBUFFER to be defined, or .NET 32*890232f2SAndroid Build Coastguard Worker // Standard 2.1. 33*890232f2SAndroid Build Coastguard Worker // 34*890232f2SAndroid Build Coastguard Worker // Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a 35*890232f2SAndroid Build Coastguard Worker // performance gain of ~15% for some operations, however doing so is potentially 36*890232f2SAndroid Build Coastguard Worker // dangerous. Do so at your own risk! 37*890232f2SAndroid Build Coastguard Worker // 38*890232f2SAndroid Build Coastguard Worker 39*890232f2SAndroid Build Coastguard Worker using System; 40*890232f2SAndroid Build Coastguard Worker using System.Collections.Generic; 41*890232f2SAndroid Build Coastguard Worker using System.IO; 42*890232f2SAndroid Build Coastguard Worker using System.Runtime.CompilerServices; 43*890232f2SAndroid Build Coastguard Worker using System.Runtime.InteropServices; 44*890232f2SAndroid Build Coastguard Worker using System.Text; 45*890232f2SAndroid Build Coastguard Worker 46*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) 47*890232f2SAndroid Build Coastguard Worker using System.Buffers.Binary; 48*890232f2SAndroid Build Coastguard Worker #endif 49*890232f2SAndroid Build Coastguard Worker 50*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && !UNSAFE_BYTEBUFFER && !NETSTANDARD2_1 51*890232f2SAndroid Build Coastguard Worker #warning ENABLE_SPAN_T requires UNSAFE_BYTEBUFFER to also be defined 52*890232f2SAndroid Build Coastguard Worker #endif 53*890232f2SAndroid Build Coastguard Worker 54*890232f2SAndroid Build Coastguard Worker namespace FlatBuffers 55*890232f2SAndroid Build Coastguard Worker { 56*890232f2SAndroid Build Coastguard Worker public abstract class ByteBufferAllocator 57*890232f2SAndroid Build Coastguard Worker { 58*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) 59*890232f2SAndroid Build Coastguard Worker public abstract Span<byte> Span { get; } 60*890232f2SAndroid Build Coastguard Worker public abstract ReadOnlySpan<byte> ReadOnlySpan { get; } 61*890232f2SAndroid Build Coastguard Worker public abstract Memory<byte> Memory { get; } 62*890232f2SAndroid Build Coastguard Worker public abstract ReadOnlyMemory<byte> ReadOnlyMemory { get; } 63*890232f2SAndroid Build Coastguard Worker 64*890232f2SAndroid Build Coastguard Worker #else 65*890232f2SAndroid Build Coastguard Worker public byte[] Buffer 66*890232f2SAndroid Build Coastguard Worker { 67*890232f2SAndroid Build Coastguard Worker get; 68*890232f2SAndroid Build Coastguard Worker protected set; 69*890232f2SAndroid Build Coastguard Worker } 70*890232f2SAndroid Build Coastguard Worker #endif 71*890232f2SAndroid Build Coastguard Worker 72*890232f2SAndroid Build Coastguard Worker public int Length 73*890232f2SAndroid Build Coastguard Worker { 74*890232f2SAndroid Build Coastguard Worker get; 75*890232f2SAndroid Build Coastguard Worker protected set; 76*890232f2SAndroid Build Coastguard Worker } 77*890232f2SAndroid Build Coastguard Worker GrowFront(int newSize)78*890232f2SAndroid Build Coastguard Worker public abstract void GrowFront(int newSize); 79*890232f2SAndroid Build Coastguard Worker } 80*890232f2SAndroid Build Coastguard Worker 81*890232f2SAndroid Build Coastguard Worker public sealed class ByteArrayAllocator : ByteBufferAllocator 82*890232f2SAndroid Build Coastguard Worker { 83*890232f2SAndroid Build Coastguard Worker private byte[] _buffer; 84*890232f2SAndroid Build Coastguard Worker ByteArrayAllocator(byte[] buffer)85*890232f2SAndroid Build Coastguard Worker public ByteArrayAllocator(byte[] buffer) 86*890232f2SAndroid Build Coastguard Worker { 87*890232f2SAndroid Build Coastguard Worker _buffer = buffer; 88*890232f2SAndroid Build Coastguard Worker InitBuffer(); 89*890232f2SAndroid Build Coastguard Worker } 90*890232f2SAndroid Build Coastguard Worker GrowFront(int newSize)91*890232f2SAndroid Build Coastguard Worker public override void GrowFront(int newSize) 92*890232f2SAndroid Build Coastguard Worker { 93*890232f2SAndroid Build Coastguard Worker if ((Length & 0xC0000000) != 0) 94*890232f2SAndroid Build Coastguard Worker throw new Exception( 95*890232f2SAndroid Build Coastguard Worker "ByteBuffer: cannot grow buffer beyond 2 gigabytes."); 96*890232f2SAndroid Build Coastguard Worker 97*890232f2SAndroid Build Coastguard Worker if (newSize < Length) 98*890232f2SAndroid Build Coastguard Worker throw new Exception("ByteBuffer: cannot truncate buffer."); 99*890232f2SAndroid Build Coastguard Worker 100*890232f2SAndroid Build Coastguard Worker byte[] newBuffer = new byte[newSize]; 101*890232f2SAndroid Build Coastguard Worker System.Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, Length); 102*890232f2SAndroid Build Coastguard Worker _buffer = newBuffer; 103*890232f2SAndroid Build Coastguard Worker InitBuffer(); 104*890232f2SAndroid Build Coastguard Worker } 105*890232f2SAndroid Build Coastguard Worker 106*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) 107*890232f2SAndroid Build Coastguard Worker public override Span<byte> Span => _buffer; 108*890232f2SAndroid Build Coastguard Worker public override ReadOnlySpan<byte> ReadOnlySpan => _buffer; 109*890232f2SAndroid Build Coastguard Worker public override Memory<byte> Memory => _buffer; 110*890232f2SAndroid Build Coastguard Worker public override ReadOnlyMemory<byte> ReadOnlyMemory => _buffer; 111*890232f2SAndroid Build Coastguard Worker #endif 112*890232f2SAndroid Build Coastguard Worker InitBuffer()113*890232f2SAndroid Build Coastguard Worker private void InitBuffer() 114*890232f2SAndroid Build Coastguard Worker { 115*890232f2SAndroid Build Coastguard Worker Length = _buffer.Length; 116*890232f2SAndroid Build Coastguard Worker #if !ENABLE_SPAN_T 117*890232f2SAndroid Build Coastguard Worker Buffer = _buffer; 118*890232f2SAndroid Build Coastguard Worker #endif 119*890232f2SAndroid Build Coastguard Worker } 120*890232f2SAndroid Build Coastguard Worker } 121*890232f2SAndroid Build Coastguard Worker 122*890232f2SAndroid Build Coastguard Worker /// <summary> 123*890232f2SAndroid Build Coastguard Worker /// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers. 124*890232f2SAndroid Build Coastguard Worker /// </summary> 125*890232f2SAndroid Build Coastguard Worker public class ByteBuffer 126*890232f2SAndroid Build Coastguard Worker { 127*890232f2SAndroid Build Coastguard Worker private ByteBufferAllocator _buffer; 128*890232f2SAndroid Build Coastguard Worker private int _pos; // Must track start of the buffer. 129*890232f2SAndroid Build Coastguard Worker ByteBuffer(ByteBufferAllocator allocator, int position)130*890232f2SAndroid Build Coastguard Worker public ByteBuffer(ByteBufferAllocator allocator, int position) 131*890232f2SAndroid Build Coastguard Worker { 132*890232f2SAndroid Build Coastguard Worker _buffer = allocator; 133*890232f2SAndroid Build Coastguard Worker _pos = position; 134*890232f2SAndroid Build Coastguard Worker } 135*890232f2SAndroid Build Coastguard Worker ByteBuffer(int size)136*890232f2SAndroid Build Coastguard Worker public ByteBuffer(int size) : this(new byte[size]) { } 137*890232f2SAndroid Build Coastguard Worker ByteBuffer(byte[] buffer)138*890232f2SAndroid Build Coastguard Worker public ByteBuffer(byte[] buffer) : this(buffer, 0) { } 139*890232f2SAndroid Build Coastguard Worker ByteBuffer(byte[] buffer, int pos)140*890232f2SAndroid Build Coastguard Worker public ByteBuffer(byte[] buffer, int pos) 141*890232f2SAndroid Build Coastguard Worker { 142*890232f2SAndroid Build Coastguard Worker _buffer = new ByteArrayAllocator(buffer); 143*890232f2SAndroid Build Coastguard Worker _pos = pos; 144*890232f2SAndroid Build Coastguard Worker } 145*890232f2SAndroid Build Coastguard Worker 146*890232f2SAndroid Build Coastguard Worker public int Position 147*890232f2SAndroid Build Coastguard Worker { 148*890232f2SAndroid Build Coastguard Worker get { return _pos; } 149*890232f2SAndroid Build Coastguard Worker set { _pos = value; } 150*890232f2SAndroid Build Coastguard Worker } 151*890232f2SAndroid Build Coastguard Worker 152*890232f2SAndroid Build Coastguard Worker public int Length { get { return _buffer.Length; } } 153*890232f2SAndroid Build Coastguard Worker Reset()154*890232f2SAndroid Build Coastguard Worker public void Reset() 155*890232f2SAndroid Build Coastguard Worker { 156*890232f2SAndroid Build Coastguard Worker _pos = 0; 157*890232f2SAndroid Build Coastguard Worker } 158*890232f2SAndroid Build Coastguard Worker 159*890232f2SAndroid Build Coastguard Worker // Create a new ByteBuffer on the same underlying data. 160*890232f2SAndroid Build Coastguard Worker // The new ByteBuffer's position will be same as this buffer's. Duplicate()161*890232f2SAndroid Build Coastguard Worker public ByteBuffer Duplicate() 162*890232f2SAndroid Build Coastguard Worker { 163*890232f2SAndroid Build Coastguard Worker return new ByteBuffer(_buffer, Position); 164*890232f2SAndroid Build Coastguard Worker } 165*890232f2SAndroid Build Coastguard Worker 166*890232f2SAndroid Build Coastguard Worker // Increases the size of the ByteBuffer, and copies the old data towards 167*890232f2SAndroid Build Coastguard Worker // the end of the new buffer. GrowFront(int newSize)168*890232f2SAndroid Build Coastguard Worker public void GrowFront(int newSize) 169*890232f2SAndroid Build Coastguard Worker { 170*890232f2SAndroid Build Coastguard Worker _buffer.GrowFront(newSize); 171*890232f2SAndroid Build Coastguard Worker } 172*890232f2SAndroid Build Coastguard Worker ToArray(int pos, int len)173*890232f2SAndroid Build Coastguard Worker public byte[] ToArray(int pos, int len) 174*890232f2SAndroid Build Coastguard Worker { 175*890232f2SAndroid Build Coastguard Worker return ToArray<byte>(pos, len); 176*890232f2SAndroid Build Coastguard Worker } 177*890232f2SAndroid Build Coastguard Worker 178*890232f2SAndroid Build Coastguard Worker /// <summary> 179*890232f2SAndroid Build Coastguard Worker /// A lookup of type sizes. Used instead of Marshal.SizeOf() which has additional 180*890232f2SAndroid Build Coastguard Worker /// overhead, but also is compatible with generic functions for simplified code. 181*890232f2SAndroid Build Coastguard Worker /// </summary> 182*890232f2SAndroid Build Coastguard Worker private static Dictionary<Type, int> genericSizes = new Dictionary<Type, int>() 183*890232f2SAndroid Build Coastguard Worker { 184*890232f2SAndroid Build Coastguard Worker { typeof(bool), sizeof(bool) }, 185*890232f2SAndroid Build Coastguard Worker { typeof(float), sizeof(float) }, 186*890232f2SAndroid Build Coastguard Worker { typeof(double), sizeof(double) }, 187*890232f2SAndroid Build Coastguard Worker { typeof(sbyte), sizeof(sbyte) }, 188*890232f2SAndroid Build Coastguard Worker { typeof(byte), sizeof(byte) }, 189*890232f2SAndroid Build Coastguard Worker { typeof(short), sizeof(short) }, 190*890232f2SAndroid Build Coastguard Worker { typeof(ushort), sizeof(ushort) }, 191*890232f2SAndroid Build Coastguard Worker { typeof(int), sizeof(int) }, 192*890232f2SAndroid Build Coastguard Worker { typeof(uint), sizeof(uint) }, 193*890232f2SAndroid Build Coastguard Worker { typeof(ulong), sizeof(ulong) }, 194*890232f2SAndroid Build Coastguard Worker { typeof(long), sizeof(long) }, 195*890232f2SAndroid Build Coastguard Worker }; 196*890232f2SAndroid Build Coastguard Worker 197*890232f2SAndroid Build Coastguard Worker /// <summary> 198*890232f2SAndroid Build Coastguard Worker /// Get the wire-size (in bytes) of a type supported by flatbuffers. 199*890232f2SAndroid Build Coastguard Worker /// </summary> 200*890232f2SAndroid Build Coastguard Worker /// <param name="t">The type to get the wire size of</param> 201*890232f2SAndroid Build Coastguard Worker /// <returns></returns> SizeOf()202*890232f2SAndroid Build Coastguard Worker public static int SizeOf<T>() 203*890232f2SAndroid Build Coastguard Worker { 204*890232f2SAndroid Build Coastguard Worker return genericSizes[typeof(T)]; 205*890232f2SAndroid Build Coastguard Worker } 206*890232f2SAndroid Build Coastguard Worker 207*890232f2SAndroid Build Coastguard Worker /// <summary> 208*890232f2SAndroid Build Coastguard Worker /// Checks if the Type provided is supported as scalar value 209*890232f2SAndroid Build Coastguard Worker /// </summary> 210*890232f2SAndroid Build Coastguard Worker /// <typeparam name="T">The Type to check</typeparam> 211*890232f2SAndroid Build Coastguard Worker /// <returns>True if the type is a scalar type that is supported, falsed otherwise</returns> IsSupportedType()212*890232f2SAndroid Build Coastguard Worker public static bool IsSupportedType<T>() 213*890232f2SAndroid Build Coastguard Worker { 214*890232f2SAndroid Build Coastguard Worker return genericSizes.ContainsKey(typeof(T)); 215*890232f2SAndroid Build Coastguard Worker } 216*890232f2SAndroid Build Coastguard Worker 217*890232f2SAndroid Build Coastguard Worker /// <summary> 218*890232f2SAndroid Build Coastguard Worker /// Get the wire-size (in bytes) of an typed array 219*890232f2SAndroid Build Coastguard Worker /// </summary> 220*890232f2SAndroid Build Coastguard Worker /// <typeparam name="T">The type of the array</typeparam> 221*890232f2SAndroid Build Coastguard Worker /// <param name="x">The array to get the size of</param> 222*890232f2SAndroid Build Coastguard Worker /// <returns>The number of bytes the array takes on wire</returns> ArraySize(T[] x)223*890232f2SAndroid Build Coastguard Worker public static int ArraySize<T>(T[] x) 224*890232f2SAndroid Build Coastguard Worker { 225*890232f2SAndroid Build Coastguard Worker return SizeOf<T>() * x.Length; 226*890232f2SAndroid Build Coastguard Worker } 227*890232f2SAndroid Build Coastguard Worker 228*890232f2SAndroid Build Coastguard Worker /// <summary> 229*890232f2SAndroid Build Coastguard Worker /// Get the wire-size (in bytes) of an typed array segment, taking only the 230*890232f2SAndroid Build Coastguard Worker /// range specified by <paramref name="x"/> into account. 231*890232f2SAndroid Build Coastguard Worker /// </summary> 232*890232f2SAndroid Build Coastguard Worker /// <typeparam name="T">The type of the array</typeparam> 233*890232f2SAndroid Build Coastguard Worker /// <param name="x">The array segment to get the size of</param> 234*890232f2SAndroid Build Coastguard Worker /// <returns>The number of bytes the array segment takes on wire</returns> ArraySize(ArraySegment<T> x)235*890232f2SAndroid Build Coastguard Worker public static int ArraySize<T>(ArraySegment<T> x) 236*890232f2SAndroid Build Coastguard Worker { 237*890232f2SAndroid Build Coastguard Worker return SizeOf<T>() * x.Count; 238*890232f2SAndroid Build Coastguard Worker } 239*890232f2SAndroid Build Coastguard Worker 240*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) ArraySize(Span<T> x)241*890232f2SAndroid Build Coastguard Worker public static int ArraySize<T>(Span<T> x) 242*890232f2SAndroid Build Coastguard Worker { 243*890232f2SAndroid Build Coastguard Worker return SizeOf<T>() * x.Length; 244*890232f2SAndroid Build Coastguard Worker } 245*890232f2SAndroid Build Coastguard Worker #endif 246*890232f2SAndroid Build Coastguard Worker 247*890232f2SAndroid Build Coastguard Worker // Get a portion of the buffer casted into an array of type T, given 248*890232f2SAndroid Build Coastguard Worker // the buffer position and length. 249*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) 250*890232f2SAndroid Build Coastguard Worker public T[] ToArray<T>(int pos, int len) 251*890232f2SAndroid Build Coastguard Worker where T : struct 252*890232f2SAndroid Build Coastguard Worker { AssertOffsetAndLengthFlatBuffers.ByteBuffer.__anon1253*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(pos, len); 254*890232f2SAndroid Build Coastguard Worker return MemoryMarshal.Cast<byte, T>(_buffer.ReadOnlySpan.Slice(pos)).Slice(0, len).ToArray(); 255*890232f2SAndroid Build Coastguard Worker } 256*890232f2SAndroid Build Coastguard Worker #else 257*890232f2SAndroid Build Coastguard Worker public T[] ToArray<T>(int pos, int len) 258*890232f2SAndroid Build Coastguard Worker where T : struct 259*890232f2SAndroid Build Coastguard Worker { AssertOffsetAndLengthFlatBuffers.ByteBuffer.__anon2260*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(pos, len); 261*890232f2SAndroid Build Coastguard Worker T[] arr = new T[len]; Buffer.BlockCopyFlatBuffers.ByteBuffer.__anon2262*890232f2SAndroid Build Coastguard Worker Buffer.BlockCopy(_buffer.Buffer, pos, arr, 0, ArraySize(arr)); 263*890232f2SAndroid Build Coastguard Worker return arr; 264*890232f2SAndroid Build Coastguard Worker } 265*890232f2SAndroid Build Coastguard Worker #endif 266*890232f2SAndroid Build Coastguard Worker ToSizedArray()267*890232f2SAndroid Build Coastguard Worker public byte[] ToSizedArray() 268*890232f2SAndroid Build Coastguard Worker { 269*890232f2SAndroid Build Coastguard Worker return ToArray<byte>(Position, Length - Position); 270*890232f2SAndroid Build Coastguard Worker } 271*890232f2SAndroid Build Coastguard Worker ToFullArray()272*890232f2SAndroid Build Coastguard Worker public byte[] ToFullArray() 273*890232f2SAndroid Build Coastguard Worker { 274*890232f2SAndroid Build Coastguard Worker return ToArray<byte>(0, Length); 275*890232f2SAndroid Build Coastguard Worker } 276*890232f2SAndroid Build Coastguard Worker 277*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) ToReadOnlyMemory(int pos, int len)278*890232f2SAndroid Build Coastguard Worker public ReadOnlyMemory<byte> ToReadOnlyMemory(int pos, int len) 279*890232f2SAndroid Build Coastguard Worker { 280*890232f2SAndroid Build Coastguard Worker return _buffer.ReadOnlyMemory.Slice(pos, len); 281*890232f2SAndroid Build Coastguard Worker } 282*890232f2SAndroid Build Coastguard Worker ToMemory(int pos, int len)283*890232f2SAndroid Build Coastguard Worker public Memory<byte> ToMemory(int pos, int len) 284*890232f2SAndroid Build Coastguard Worker { 285*890232f2SAndroid Build Coastguard Worker return _buffer.Memory.Slice(pos, len); 286*890232f2SAndroid Build Coastguard Worker } 287*890232f2SAndroid Build Coastguard Worker ToSpan(int pos, int len)288*890232f2SAndroid Build Coastguard Worker public Span<byte> ToSpan(int pos, int len) 289*890232f2SAndroid Build Coastguard Worker { 290*890232f2SAndroid Build Coastguard Worker return _buffer.Span.Slice(pos, len); 291*890232f2SAndroid Build Coastguard Worker } 292*890232f2SAndroid Build Coastguard Worker #else ToArraySegment(int pos, int len)293*890232f2SAndroid Build Coastguard Worker public ArraySegment<byte> ToArraySegment(int pos, int len) 294*890232f2SAndroid Build Coastguard Worker { 295*890232f2SAndroid Build Coastguard Worker return new ArraySegment<byte>(_buffer.Buffer, pos, len); 296*890232f2SAndroid Build Coastguard Worker } 297*890232f2SAndroid Build Coastguard Worker ToMemoryStream(int pos, int len)298*890232f2SAndroid Build Coastguard Worker public MemoryStream ToMemoryStream(int pos, int len) 299*890232f2SAndroid Build Coastguard Worker { 300*890232f2SAndroid Build Coastguard Worker return new MemoryStream(_buffer.Buffer, pos, len); 301*890232f2SAndroid Build Coastguard Worker } 302*890232f2SAndroid Build Coastguard Worker #endif 303*890232f2SAndroid Build Coastguard Worker 304*890232f2SAndroid Build Coastguard Worker #if !UNSAFE_BYTEBUFFER 305*890232f2SAndroid Build Coastguard Worker // A conversion union where all the members are overlapping. This allows to reinterpret the bytes of one type 306*890232f2SAndroid Build Coastguard Worker // as another, without additional copies. 307*890232f2SAndroid Build Coastguard Worker [StructLayout(LayoutKind.Explicit)] 308*890232f2SAndroid Build Coastguard Worker struct ConversionUnion 309*890232f2SAndroid Build Coastguard Worker { 310*890232f2SAndroid Build Coastguard Worker [FieldOffset(0)] public int intValue; 311*890232f2SAndroid Build Coastguard Worker [FieldOffset(0)] public float floatValue; 312*890232f2SAndroid Build Coastguard Worker } 313*890232f2SAndroid Build Coastguard Worker #endif // !UNSAFE_BYTEBUFFER 314*890232f2SAndroid Build Coastguard Worker 315*890232f2SAndroid Build Coastguard Worker // Helper functions for the unsafe version. ReverseBytes(ushort input)316*890232f2SAndroid Build Coastguard Worker static public ushort ReverseBytes(ushort input) 317*890232f2SAndroid Build Coastguard Worker { 318*890232f2SAndroid Build Coastguard Worker return (ushort)(((input & 0x00FFU) << 8) | 319*890232f2SAndroid Build Coastguard Worker ((input & 0xFF00U) >> 8)); 320*890232f2SAndroid Build Coastguard Worker } ReverseBytes(uint input)321*890232f2SAndroid Build Coastguard Worker static public uint ReverseBytes(uint input) 322*890232f2SAndroid Build Coastguard Worker { 323*890232f2SAndroid Build Coastguard Worker return ((input & 0x000000FFU) << 24) | 324*890232f2SAndroid Build Coastguard Worker ((input & 0x0000FF00U) << 8) | 325*890232f2SAndroid Build Coastguard Worker ((input & 0x00FF0000U) >> 8) | 326*890232f2SAndroid Build Coastguard Worker ((input & 0xFF000000U) >> 24); 327*890232f2SAndroid Build Coastguard Worker } ReverseBytes(ulong input)328*890232f2SAndroid Build Coastguard Worker static public ulong ReverseBytes(ulong input) 329*890232f2SAndroid Build Coastguard Worker { 330*890232f2SAndroid Build Coastguard Worker return (((input & 0x00000000000000FFUL) << 56) | 331*890232f2SAndroid Build Coastguard Worker ((input & 0x000000000000FF00UL) << 40) | 332*890232f2SAndroid Build Coastguard Worker ((input & 0x0000000000FF0000UL) << 24) | 333*890232f2SAndroid Build Coastguard Worker ((input & 0x00000000FF000000UL) << 8) | 334*890232f2SAndroid Build Coastguard Worker ((input & 0x000000FF00000000UL) >> 8) | 335*890232f2SAndroid Build Coastguard Worker ((input & 0x0000FF0000000000UL) >> 24) | 336*890232f2SAndroid Build Coastguard Worker ((input & 0x00FF000000000000UL) >> 40) | 337*890232f2SAndroid Build Coastguard Worker ((input & 0xFF00000000000000UL) >> 56)); 338*890232f2SAndroid Build Coastguard Worker } 339*890232f2SAndroid Build Coastguard Worker 340*890232f2SAndroid Build Coastguard Worker #if !UNSAFE_BYTEBUFFER && (!ENABLE_SPAN_T || !NETSTANDARD2_1) 341*890232f2SAndroid Build Coastguard Worker // Helper functions for the safe (but slower) version. WriteLittleEndian(int offset, int count, ulong data)342*890232f2SAndroid Build Coastguard Worker protected void WriteLittleEndian(int offset, int count, ulong data) 343*890232f2SAndroid Build Coastguard Worker { 344*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 345*890232f2SAndroid Build Coastguard Worker { 346*890232f2SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) 347*890232f2SAndroid Build Coastguard Worker { 348*890232f2SAndroid Build Coastguard Worker _buffer.Buffer[offset + i] = (byte)(data >> i * 8); 349*890232f2SAndroid Build Coastguard Worker } 350*890232f2SAndroid Build Coastguard Worker } 351*890232f2SAndroid Build Coastguard Worker else 352*890232f2SAndroid Build Coastguard Worker { 353*890232f2SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) 354*890232f2SAndroid Build Coastguard Worker { 355*890232f2SAndroid Build Coastguard Worker _buffer.Buffer[offset + count - 1 - i] = (byte)(data >> i * 8); 356*890232f2SAndroid Build Coastguard Worker } 357*890232f2SAndroid Build Coastguard Worker } 358*890232f2SAndroid Build Coastguard Worker } 359*890232f2SAndroid Build Coastguard Worker ReadLittleEndian(int offset, int count)360*890232f2SAndroid Build Coastguard Worker protected ulong ReadLittleEndian(int offset, int count) 361*890232f2SAndroid Build Coastguard Worker { 362*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, count); 363*890232f2SAndroid Build Coastguard Worker ulong r = 0; 364*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 365*890232f2SAndroid Build Coastguard Worker { 366*890232f2SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) 367*890232f2SAndroid Build Coastguard Worker { 368*890232f2SAndroid Build Coastguard Worker r |= (ulong)_buffer.Buffer[offset + i] << i * 8; 369*890232f2SAndroid Build Coastguard Worker } 370*890232f2SAndroid Build Coastguard Worker } 371*890232f2SAndroid Build Coastguard Worker else 372*890232f2SAndroid Build Coastguard Worker { 373*890232f2SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) 374*890232f2SAndroid Build Coastguard Worker { 375*890232f2SAndroid Build Coastguard Worker r |= (ulong)_buffer.Buffer[offset + count - 1 - i] << i * 8; 376*890232f2SAndroid Build Coastguard Worker } 377*890232f2SAndroid Build Coastguard Worker } 378*890232f2SAndroid Build Coastguard Worker return r; 379*890232f2SAndroid Build Coastguard Worker } 380*890232f2SAndroid Build Coastguard Worker #elif ENABLE_SPAN_T && NETSTANDARD2_1 WriteLittleEndian(int offset, int count, ulong data)381*890232f2SAndroid Build Coastguard Worker protected void WriteLittleEndian(int offset, int count, ulong data) 382*890232f2SAndroid Build Coastguard Worker { 383*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 384*890232f2SAndroid Build Coastguard Worker { 385*890232f2SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) 386*890232f2SAndroid Build Coastguard Worker { 387*890232f2SAndroid Build Coastguard Worker _buffer.Span[offset + i] = (byte)(data >> i * 8); 388*890232f2SAndroid Build Coastguard Worker } 389*890232f2SAndroid Build Coastguard Worker } 390*890232f2SAndroid Build Coastguard Worker else 391*890232f2SAndroid Build Coastguard Worker { 392*890232f2SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) 393*890232f2SAndroid Build Coastguard Worker { 394*890232f2SAndroid Build Coastguard Worker _buffer.Span[offset + count - 1 - i] = (byte)(data >> i * 8); 395*890232f2SAndroid Build Coastguard Worker } 396*890232f2SAndroid Build Coastguard Worker } 397*890232f2SAndroid Build Coastguard Worker } 398*890232f2SAndroid Build Coastguard Worker ReadLittleEndian(int offset, int count)399*890232f2SAndroid Build Coastguard Worker protected ulong ReadLittleEndian(int offset, int count) 400*890232f2SAndroid Build Coastguard Worker { 401*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, count); 402*890232f2SAndroid Build Coastguard Worker ulong r = 0; 403*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 404*890232f2SAndroid Build Coastguard Worker { 405*890232f2SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) 406*890232f2SAndroid Build Coastguard Worker { 407*890232f2SAndroid Build Coastguard Worker r |= (ulong)_buffer.Span[offset + i] << i * 8; 408*890232f2SAndroid Build Coastguard Worker } 409*890232f2SAndroid Build Coastguard Worker } 410*890232f2SAndroid Build Coastguard Worker else 411*890232f2SAndroid Build Coastguard Worker { 412*890232f2SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) 413*890232f2SAndroid Build Coastguard Worker { 414*890232f2SAndroid Build Coastguard Worker r |= (ulong)_buffer.Span[offset + count - 1 - i] << i * 8; 415*890232f2SAndroid Build Coastguard Worker } 416*890232f2SAndroid Build Coastguard Worker } 417*890232f2SAndroid Build Coastguard Worker return r; 418*890232f2SAndroid Build Coastguard Worker } 419*890232f2SAndroid Build Coastguard Worker #endif 420*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(int offset, int length)421*890232f2SAndroid Build Coastguard Worker private void AssertOffsetAndLength(int offset, int length) 422*890232f2SAndroid Build Coastguard Worker { 423*890232f2SAndroid Build Coastguard Worker #if !BYTEBUFFER_NO_BOUNDS_CHECK 424*890232f2SAndroid Build Coastguard Worker if (offset < 0 || 425*890232f2SAndroid Build Coastguard Worker offset > _buffer.Length - length) 426*890232f2SAndroid Build Coastguard Worker throw new ArgumentOutOfRangeException(); 427*890232f2SAndroid Build Coastguard Worker #endif 428*890232f2SAndroid Build Coastguard Worker } 429*890232f2SAndroid Build Coastguard Worker 430*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) 431*890232f2SAndroid Build Coastguard Worker PutSbyte(int offset, sbyte value)432*890232f2SAndroid Build Coastguard Worker public void PutSbyte(int offset, sbyte value) 433*890232f2SAndroid Build Coastguard Worker { 434*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(sbyte)); 435*890232f2SAndroid Build Coastguard Worker _buffer.Span[offset] = (byte)value; 436*890232f2SAndroid Build Coastguard Worker } 437*890232f2SAndroid Build Coastguard Worker PutByte(int offset, byte value)438*890232f2SAndroid Build Coastguard Worker public void PutByte(int offset, byte value) 439*890232f2SAndroid Build Coastguard Worker { 440*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(byte)); 441*890232f2SAndroid Build Coastguard Worker _buffer.Span[offset] = value; 442*890232f2SAndroid Build Coastguard Worker } 443*890232f2SAndroid Build Coastguard Worker PutByte(int offset, byte value, int count)444*890232f2SAndroid Build Coastguard Worker public void PutByte(int offset, byte value, int count) 445*890232f2SAndroid Build Coastguard Worker { 446*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(byte) * count); 447*890232f2SAndroid Build Coastguard Worker Span<byte> span = _buffer.Span.Slice(offset, count); 448*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < span.Length; ++i) 449*890232f2SAndroid Build Coastguard Worker span[i] = value; 450*890232f2SAndroid Build Coastguard Worker } 451*890232f2SAndroid Build Coastguard Worker #else PutSbyte(int offset, sbyte value)452*890232f2SAndroid Build Coastguard Worker public void PutSbyte(int offset, sbyte value) 453*890232f2SAndroid Build Coastguard Worker { 454*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(sbyte)); 455*890232f2SAndroid Build Coastguard Worker _buffer.Buffer[offset] = (byte)value; 456*890232f2SAndroid Build Coastguard Worker } 457*890232f2SAndroid Build Coastguard Worker PutByte(int offset, byte value)458*890232f2SAndroid Build Coastguard Worker public void PutByte(int offset, byte value) 459*890232f2SAndroid Build Coastguard Worker { 460*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(byte)); 461*890232f2SAndroid Build Coastguard Worker _buffer.Buffer[offset] = value; 462*890232f2SAndroid Build Coastguard Worker } 463*890232f2SAndroid Build Coastguard Worker PutByte(int offset, byte value, int count)464*890232f2SAndroid Build Coastguard Worker public void PutByte(int offset, byte value, int count) 465*890232f2SAndroid Build Coastguard Worker { 466*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(byte) * count); 467*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < count; ++i) 468*890232f2SAndroid Build Coastguard Worker _buffer.Buffer[offset + i] = value; 469*890232f2SAndroid Build Coastguard Worker } 470*890232f2SAndroid Build Coastguard Worker #endif 471*890232f2SAndroid Build Coastguard Worker 472*890232f2SAndroid Build Coastguard Worker // this method exists in order to conform with Java ByteBuffer standards Put(int offset, byte value)473*890232f2SAndroid Build Coastguard Worker public void Put(int offset, byte value) 474*890232f2SAndroid Build Coastguard Worker { 475*890232f2SAndroid Build Coastguard Worker PutByte(offset, value); 476*890232f2SAndroid Build Coastguard Worker } 477*890232f2SAndroid Build Coastguard Worker 478*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && UNSAFE_BYTEBUFFER PutStringUTF8(int offset, string value)479*890232f2SAndroid Build Coastguard Worker public unsafe void PutStringUTF8(int offset, string value) 480*890232f2SAndroid Build Coastguard Worker { 481*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, value.Length); 482*890232f2SAndroid Build Coastguard Worker fixed (char* s = value) 483*890232f2SAndroid Build Coastguard Worker { 484*890232f2SAndroid Build Coastguard Worker fixed (byte* buffer = &MemoryMarshal.GetReference(_buffer.Span)) 485*890232f2SAndroid Build Coastguard Worker { 486*890232f2SAndroid Build Coastguard Worker Encoding.UTF8.GetBytes(s, value.Length, buffer + offset, Length - offset); 487*890232f2SAndroid Build Coastguard Worker } 488*890232f2SAndroid Build Coastguard Worker } 489*890232f2SAndroid Build Coastguard Worker } 490*890232f2SAndroid Build Coastguard Worker #elif ENABLE_SPAN_T && NETSTANDARD2_1 PutStringUTF8(int offset, string value)491*890232f2SAndroid Build Coastguard Worker public void PutStringUTF8(int offset, string value) 492*890232f2SAndroid Build Coastguard Worker { 493*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, value.Length); 494*890232f2SAndroid Build Coastguard Worker Encoding.UTF8.GetBytes(value.AsSpan().Slice(0, value.Length), 495*890232f2SAndroid Build Coastguard Worker _buffer.Span.Slice(offset)); 496*890232f2SAndroid Build Coastguard Worker } 497*890232f2SAndroid Build Coastguard Worker #else PutStringUTF8(int offset, string value)498*890232f2SAndroid Build Coastguard Worker public void PutStringUTF8(int offset, string value) 499*890232f2SAndroid Build Coastguard Worker { 500*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, value.Length); 501*890232f2SAndroid Build Coastguard Worker Encoding.UTF8.GetBytes(value, 0, value.Length, 502*890232f2SAndroid Build Coastguard Worker _buffer.Buffer, offset); 503*890232f2SAndroid Build Coastguard Worker } 504*890232f2SAndroid Build Coastguard Worker #endif 505*890232f2SAndroid Build Coastguard Worker 506*890232f2SAndroid Build Coastguard Worker #if UNSAFE_BYTEBUFFER 507*890232f2SAndroid Build Coastguard Worker // Unsafe but more efficient versions of Put*. PutShort(int offset, short value)508*890232f2SAndroid Build Coastguard Worker public void PutShort(int offset, short value) 509*890232f2SAndroid Build Coastguard Worker { 510*890232f2SAndroid Build Coastguard Worker PutUshort(offset, (ushort)value); 511*890232f2SAndroid Build Coastguard Worker } 512*890232f2SAndroid Build Coastguard Worker PutUshort(int offset, ushort value)513*890232f2SAndroid Build Coastguard Worker public unsafe void PutUshort(int offset, ushort value) 514*890232f2SAndroid Build Coastguard Worker { 515*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(ushort)); 516*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 517*890232f2SAndroid Build Coastguard Worker Span<byte> span = _buffer.Span.Slice(offset); 518*890232f2SAndroid Build Coastguard Worker BinaryPrimitives.WriteUInt16LittleEndian(span, value); 519*890232f2SAndroid Build Coastguard Worker #else 520*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 521*890232f2SAndroid Build Coastguard Worker { 522*890232f2SAndroid Build Coastguard Worker *(ushort*)(ptr + offset) = BitConverter.IsLittleEndian 523*890232f2SAndroid Build Coastguard Worker ? value 524*890232f2SAndroid Build Coastguard Worker : ReverseBytes(value); 525*890232f2SAndroid Build Coastguard Worker } 526*890232f2SAndroid Build Coastguard Worker #endif 527*890232f2SAndroid Build Coastguard Worker } 528*890232f2SAndroid Build Coastguard Worker PutInt(int offset, int value)529*890232f2SAndroid Build Coastguard Worker public void PutInt(int offset, int value) 530*890232f2SAndroid Build Coastguard Worker { 531*890232f2SAndroid Build Coastguard Worker PutUint(offset, (uint)value); 532*890232f2SAndroid Build Coastguard Worker } 533*890232f2SAndroid Build Coastguard Worker PutUint(int offset, uint value)534*890232f2SAndroid Build Coastguard Worker public unsafe void PutUint(int offset, uint value) 535*890232f2SAndroid Build Coastguard Worker { 536*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(uint)); 537*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 538*890232f2SAndroid Build Coastguard Worker Span<byte> span = _buffer.Span.Slice(offset); 539*890232f2SAndroid Build Coastguard Worker BinaryPrimitives.WriteUInt32LittleEndian(span, value); 540*890232f2SAndroid Build Coastguard Worker #else 541*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 542*890232f2SAndroid Build Coastguard Worker { 543*890232f2SAndroid Build Coastguard Worker *(uint*)(ptr + offset) = BitConverter.IsLittleEndian 544*890232f2SAndroid Build Coastguard Worker ? value 545*890232f2SAndroid Build Coastguard Worker : ReverseBytes(value); 546*890232f2SAndroid Build Coastguard Worker } 547*890232f2SAndroid Build Coastguard Worker #endif 548*890232f2SAndroid Build Coastguard Worker } 549*890232f2SAndroid Build Coastguard Worker PutLong(int offset, long value)550*890232f2SAndroid Build Coastguard Worker public unsafe void PutLong(int offset, long value) 551*890232f2SAndroid Build Coastguard Worker { 552*890232f2SAndroid Build Coastguard Worker PutUlong(offset, (ulong)value); 553*890232f2SAndroid Build Coastguard Worker } 554*890232f2SAndroid Build Coastguard Worker PutUlong(int offset, ulong value)555*890232f2SAndroid Build Coastguard Worker public unsafe void PutUlong(int offset, ulong value) 556*890232f2SAndroid Build Coastguard Worker { 557*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(ulong)); 558*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 559*890232f2SAndroid Build Coastguard Worker Span<byte> span = _buffer.Span.Slice(offset); 560*890232f2SAndroid Build Coastguard Worker BinaryPrimitives.WriteUInt64LittleEndian(span, value); 561*890232f2SAndroid Build Coastguard Worker #else 562*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 563*890232f2SAndroid Build Coastguard Worker { 564*890232f2SAndroid Build Coastguard Worker *(ulong*)(ptr + offset) = BitConverter.IsLittleEndian 565*890232f2SAndroid Build Coastguard Worker ? value 566*890232f2SAndroid Build Coastguard Worker : ReverseBytes(value); 567*890232f2SAndroid Build Coastguard Worker } 568*890232f2SAndroid Build Coastguard Worker #endif 569*890232f2SAndroid Build Coastguard Worker } 570*890232f2SAndroid Build Coastguard Worker PutFloat(int offset, float value)571*890232f2SAndroid Build Coastguard Worker public unsafe void PutFloat(int offset, float value) 572*890232f2SAndroid Build Coastguard Worker { 573*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(float)); 574*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 575*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span)) 576*890232f2SAndroid Build Coastguard Worker #else 577*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 578*890232f2SAndroid Build Coastguard Worker #endif 579*890232f2SAndroid Build Coastguard Worker { 580*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 581*890232f2SAndroid Build Coastguard Worker { 582*890232f2SAndroid Build Coastguard Worker *(float*)(ptr + offset) = value; 583*890232f2SAndroid Build Coastguard Worker } 584*890232f2SAndroid Build Coastguard Worker else 585*890232f2SAndroid Build Coastguard Worker { 586*890232f2SAndroid Build Coastguard Worker *(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value)); 587*890232f2SAndroid Build Coastguard Worker } 588*890232f2SAndroid Build Coastguard Worker } 589*890232f2SAndroid Build Coastguard Worker } 590*890232f2SAndroid Build Coastguard Worker PutDouble(int offset, double value)591*890232f2SAndroid Build Coastguard Worker public unsafe void PutDouble(int offset, double value) 592*890232f2SAndroid Build Coastguard Worker { 593*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(double)); 594*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 595*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span)) 596*890232f2SAndroid Build Coastguard Worker #else 597*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 598*890232f2SAndroid Build Coastguard Worker #endif 599*890232f2SAndroid Build Coastguard Worker { 600*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 601*890232f2SAndroid Build Coastguard Worker { 602*890232f2SAndroid Build Coastguard Worker *(double*)(ptr + offset) = value; 603*890232f2SAndroid Build Coastguard Worker } 604*890232f2SAndroid Build Coastguard Worker else 605*890232f2SAndroid Build Coastguard Worker { 606*890232f2SAndroid Build Coastguard Worker *(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(&value)); 607*890232f2SAndroid Build Coastguard Worker } 608*890232f2SAndroid Build Coastguard Worker } 609*890232f2SAndroid Build Coastguard Worker } 610*890232f2SAndroid Build Coastguard Worker #else // !UNSAFE_BYTEBUFFER 611*890232f2SAndroid Build Coastguard Worker // Slower versions of Put* for when unsafe code is not allowed. PutShort(int offset, short value)612*890232f2SAndroid Build Coastguard Worker public void PutShort(int offset, short value) 613*890232f2SAndroid Build Coastguard Worker { 614*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(short)); 615*890232f2SAndroid Build Coastguard Worker WriteLittleEndian(offset, sizeof(short), (ulong)value); 616*890232f2SAndroid Build Coastguard Worker } 617*890232f2SAndroid Build Coastguard Worker PutUshort(int offset, ushort value)618*890232f2SAndroid Build Coastguard Worker public void PutUshort(int offset, ushort value) 619*890232f2SAndroid Build Coastguard Worker { 620*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(ushort)); 621*890232f2SAndroid Build Coastguard Worker WriteLittleEndian(offset, sizeof(ushort), (ulong)value); 622*890232f2SAndroid Build Coastguard Worker } 623*890232f2SAndroid Build Coastguard Worker PutInt(int offset, int value)624*890232f2SAndroid Build Coastguard Worker public void PutInt(int offset, int value) 625*890232f2SAndroid Build Coastguard Worker { 626*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(int)); 627*890232f2SAndroid Build Coastguard Worker WriteLittleEndian(offset, sizeof(int), (ulong)value); 628*890232f2SAndroid Build Coastguard Worker } 629*890232f2SAndroid Build Coastguard Worker PutUint(int offset, uint value)630*890232f2SAndroid Build Coastguard Worker public void PutUint(int offset, uint value) 631*890232f2SAndroid Build Coastguard Worker { 632*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(uint)); 633*890232f2SAndroid Build Coastguard Worker WriteLittleEndian(offset, sizeof(uint), (ulong)value); 634*890232f2SAndroid Build Coastguard Worker } 635*890232f2SAndroid Build Coastguard Worker PutLong(int offset, long value)636*890232f2SAndroid Build Coastguard Worker public void PutLong(int offset, long value) 637*890232f2SAndroid Build Coastguard Worker { 638*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(long)); 639*890232f2SAndroid Build Coastguard Worker WriteLittleEndian(offset, sizeof(long), (ulong)value); 640*890232f2SAndroid Build Coastguard Worker } 641*890232f2SAndroid Build Coastguard Worker PutUlong(int offset, ulong value)642*890232f2SAndroid Build Coastguard Worker public void PutUlong(int offset, ulong value) 643*890232f2SAndroid Build Coastguard Worker { 644*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(ulong)); 645*890232f2SAndroid Build Coastguard Worker WriteLittleEndian(offset, sizeof(ulong), value); 646*890232f2SAndroid Build Coastguard Worker } 647*890232f2SAndroid Build Coastguard Worker PutFloat(int offset, float value)648*890232f2SAndroid Build Coastguard Worker public void PutFloat(int offset, float value) 649*890232f2SAndroid Build Coastguard Worker { 650*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(float)); 651*890232f2SAndroid Build Coastguard Worker // TODO(derekbailey): use BitConvert.SingleToInt32Bits() whenever flatbuffers upgrades to a .NET version 652*890232f2SAndroid Build Coastguard Worker // that contains it. 653*890232f2SAndroid Build Coastguard Worker ConversionUnion union; 654*890232f2SAndroid Build Coastguard Worker union.intValue = 0; 655*890232f2SAndroid Build Coastguard Worker union.floatValue = value; 656*890232f2SAndroid Build Coastguard Worker WriteLittleEndian(offset, sizeof(float), (ulong)union.intValue); 657*890232f2SAndroid Build Coastguard Worker } 658*890232f2SAndroid Build Coastguard Worker PutDouble(int offset, double value)659*890232f2SAndroid Build Coastguard Worker public void PutDouble(int offset, double value) 660*890232f2SAndroid Build Coastguard Worker { 661*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(double)); 662*890232f2SAndroid Build Coastguard Worker WriteLittleEndian(offset, sizeof(double), (ulong)BitConverter.DoubleToInt64Bits(value)); 663*890232f2SAndroid Build Coastguard Worker } 664*890232f2SAndroid Build Coastguard Worker 665*890232f2SAndroid Build Coastguard Worker #endif // UNSAFE_BYTEBUFFER 666*890232f2SAndroid Build Coastguard Worker 667*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) GetSbyte(int index)668*890232f2SAndroid Build Coastguard Worker public sbyte GetSbyte(int index) 669*890232f2SAndroid Build Coastguard Worker { 670*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(index, sizeof(sbyte)); 671*890232f2SAndroid Build Coastguard Worker return (sbyte)_buffer.ReadOnlySpan[index]; 672*890232f2SAndroid Build Coastguard Worker } 673*890232f2SAndroid Build Coastguard Worker Get(int index)674*890232f2SAndroid Build Coastguard Worker public byte Get(int index) 675*890232f2SAndroid Build Coastguard Worker { 676*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(index, sizeof(byte)); 677*890232f2SAndroid Build Coastguard Worker return _buffer.ReadOnlySpan[index]; 678*890232f2SAndroid Build Coastguard Worker } 679*890232f2SAndroid Build Coastguard Worker #else GetSbyte(int index)680*890232f2SAndroid Build Coastguard Worker public sbyte GetSbyte(int index) 681*890232f2SAndroid Build Coastguard Worker { 682*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(index, sizeof(sbyte)); 683*890232f2SAndroid Build Coastguard Worker return (sbyte)_buffer.Buffer[index]; 684*890232f2SAndroid Build Coastguard Worker } 685*890232f2SAndroid Build Coastguard Worker Get(int index)686*890232f2SAndroid Build Coastguard Worker public byte Get(int index) 687*890232f2SAndroid Build Coastguard Worker { 688*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(index, sizeof(byte)); 689*890232f2SAndroid Build Coastguard Worker return _buffer.Buffer[index]; 690*890232f2SAndroid Build Coastguard Worker } 691*890232f2SAndroid Build Coastguard Worker #endif 692*890232f2SAndroid Build Coastguard Worker 693*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && UNSAFE_BYTEBUFFER GetStringUTF8(int startPos, int len)694*890232f2SAndroid Build Coastguard Worker public unsafe string GetStringUTF8(int startPos, int len) 695*890232f2SAndroid Build Coastguard Worker { 696*890232f2SAndroid Build Coastguard Worker fixed (byte* buffer = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan.Slice(startPos))) 697*890232f2SAndroid Build Coastguard Worker { 698*890232f2SAndroid Build Coastguard Worker return Encoding.UTF8.GetString(buffer, len); 699*890232f2SAndroid Build Coastguard Worker } 700*890232f2SAndroid Build Coastguard Worker } 701*890232f2SAndroid Build Coastguard Worker #elif ENABLE_SPAN_T && NETSTANDARD2_1 GetStringUTF8(int startPos, int len)702*890232f2SAndroid Build Coastguard Worker public string GetStringUTF8(int startPos, int len) 703*890232f2SAndroid Build Coastguard Worker { 704*890232f2SAndroid Build Coastguard Worker return Encoding.UTF8.GetString(_buffer.Span.Slice(startPos, len)); 705*890232f2SAndroid Build Coastguard Worker } 706*890232f2SAndroid Build Coastguard Worker #else GetStringUTF8(int startPos, int len)707*890232f2SAndroid Build Coastguard Worker public string GetStringUTF8(int startPos, int len) 708*890232f2SAndroid Build Coastguard Worker { 709*890232f2SAndroid Build Coastguard Worker return Encoding.UTF8.GetString(_buffer.Buffer, startPos, len); 710*890232f2SAndroid Build Coastguard Worker } 711*890232f2SAndroid Build Coastguard Worker #endif 712*890232f2SAndroid Build Coastguard Worker 713*890232f2SAndroid Build Coastguard Worker #if UNSAFE_BYTEBUFFER 714*890232f2SAndroid Build Coastguard Worker // Unsafe but more efficient versions of Get*. GetShort(int offset)715*890232f2SAndroid Build Coastguard Worker public short GetShort(int offset) 716*890232f2SAndroid Build Coastguard Worker { 717*890232f2SAndroid Build Coastguard Worker return (short)GetUshort(offset); 718*890232f2SAndroid Build Coastguard Worker } 719*890232f2SAndroid Build Coastguard Worker GetUshort(int offset)720*890232f2SAndroid Build Coastguard Worker public unsafe ushort GetUshort(int offset) 721*890232f2SAndroid Build Coastguard Worker { 722*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(ushort)); 723*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 724*890232f2SAndroid Build Coastguard Worker ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset); 725*890232f2SAndroid Build Coastguard Worker return BinaryPrimitives.ReadUInt16LittleEndian(span); 726*890232f2SAndroid Build Coastguard Worker #else 727*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 728*890232f2SAndroid Build Coastguard Worker { 729*890232f2SAndroid Build Coastguard Worker return BitConverter.IsLittleEndian 730*890232f2SAndroid Build Coastguard Worker ? *(ushort*)(ptr + offset) 731*890232f2SAndroid Build Coastguard Worker : ReverseBytes(*(ushort*)(ptr + offset)); 732*890232f2SAndroid Build Coastguard Worker } 733*890232f2SAndroid Build Coastguard Worker #endif 734*890232f2SAndroid Build Coastguard Worker } 735*890232f2SAndroid Build Coastguard Worker GetInt(int offset)736*890232f2SAndroid Build Coastguard Worker public int GetInt(int offset) 737*890232f2SAndroid Build Coastguard Worker { 738*890232f2SAndroid Build Coastguard Worker return (int)GetUint(offset); 739*890232f2SAndroid Build Coastguard Worker } 740*890232f2SAndroid Build Coastguard Worker GetUint(int offset)741*890232f2SAndroid Build Coastguard Worker public unsafe uint GetUint(int offset) 742*890232f2SAndroid Build Coastguard Worker { 743*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(uint)); 744*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 745*890232f2SAndroid Build Coastguard Worker ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset); 746*890232f2SAndroid Build Coastguard Worker return BinaryPrimitives.ReadUInt32LittleEndian(span); 747*890232f2SAndroid Build Coastguard Worker #else 748*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 749*890232f2SAndroid Build Coastguard Worker { 750*890232f2SAndroid Build Coastguard Worker return BitConverter.IsLittleEndian 751*890232f2SAndroid Build Coastguard Worker ? *(uint*)(ptr + offset) 752*890232f2SAndroid Build Coastguard Worker : ReverseBytes(*(uint*)(ptr + offset)); 753*890232f2SAndroid Build Coastguard Worker } 754*890232f2SAndroid Build Coastguard Worker #endif 755*890232f2SAndroid Build Coastguard Worker } 756*890232f2SAndroid Build Coastguard Worker GetLong(int offset)757*890232f2SAndroid Build Coastguard Worker public long GetLong(int offset) 758*890232f2SAndroid Build Coastguard Worker { 759*890232f2SAndroid Build Coastguard Worker return (long)GetUlong(offset); 760*890232f2SAndroid Build Coastguard Worker } 761*890232f2SAndroid Build Coastguard Worker GetUlong(int offset)762*890232f2SAndroid Build Coastguard Worker public unsafe ulong GetUlong(int offset) 763*890232f2SAndroid Build Coastguard Worker { 764*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(ulong)); 765*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 766*890232f2SAndroid Build Coastguard Worker ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset); 767*890232f2SAndroid Build Coastguard Worker return BinaryPrimitives.ReadUInt64LittleEndian(span); 768*890232f2SAndroid Build Coastguard Worker #else 769*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 770*890232f2SAndroid Build Coastguard Worker { 771*890232f2SAndroid Build Coastguard Worker return BitConverter.IsLittleEndian 772*890232f2SAndroid Build Coastguard Worker ? *(ulong*)(ptr + offset) 773*890232f2SAndroid Build Coastguard Worker : ReverseBytes(*(ulong*)(ptr + offset)); 774*890232f2SAndroid Build Coastguard Worker } 775*890232f2SAndroid Build Coastguard Worker #endif 776*890232f2SAndroid Build Coastguard Worker } 777*890232f2SAndroid Build Coastguard Worker GetFloat(int offset)778*890232f2SAndroid Build Coastguard Worker public unsafe float GetFloat(int offset) 779*890232f2SAndroid Build Coastguard Worker { 780*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(float)); 781*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 782*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan)) 783*890232f2SAndroid Build Coastguard Worker #else 784*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 785*890232f2SAndroid Build Coastguard Worker #endif 786*890232f2SAndroid Build Coastguard Worker { 787*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 788*890232f2SAndroid Build Coastguard Worker { 789*890232f2SAndroid Build Coastguard Worker return *(float*)(ptr + offset); 790*890232f2SAndroid Build Coastguard Worker } 791*890232f2SAndroid Build Coastguard Worker else 792*890232f2SAndroid Build Coastguard Worker { 793*890232f2SAndroid Build Coastguard Worker uint uvalue = ReverseBytes(*(uint*)(ptr + offset)); 794*890232f2SAndroid Build Coastguard Worker return *(float*)(&uvalue); 795*890232f2SAndroid Build Coastguard Worker } 796*890232f2SAndroid Build Coastguard Worker } 797*890232f2SAndroid Build Coastguard Worker } 798*890232f2SAndroid Build Coastguard Worker GetDouble(int offset)799*890232f2SAndroid Build Coastguard Worker public unsafe double GetDouble(int offset) 800*890232f2SAndroid Build Coastguard Worker { 801*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeof(double)); 802*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T // && UNSAFE_BYTEBUFFER 803*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan)) 804*890232f2SAndroid Build Coastguard Worker #else 805*890232f2SAndroid Build Coastguard Worker fixed (byte* ptr = _buffer.Buffer) 806*890232f2SAndroid Build Coastguard Worker #endif 807*890232f2SAndroid Build Coastguard Worker { 808*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 809*890232f2SAndroid Build Coastguard Worker { 810*890232f2SAndroid Build Coastguard Worker return *(double*)(ptr + offset); 811*890232f2SAndroid Build Coastguard Worker } 812*890232f2SAndroid Build Coastguard Worker else 813*890232f2SAndroid Build Coastguard Worker { 814*890232f2SAndroid Build Coastguard Worker ulong uvalue = ReverseBytes(*(ulong*)(ptr + offset)); 815*890232f2SAndroid Build Coastguard Worker return *(double*)(&uvalue); 816*890232f2SAndroid Build Coastguard Worker } 817*890232f2SAndroid Build Coastguard Worker } 818*890232f2SAndroid Build Coastguard Worker } 819*890232f2SAndroid Build Coastguard Worker #else // !UNSAFE_BYTEBUFFER 820*890232f2SAndroid Build Coastguard Worker // Slower versions of Get* for when unsafe code is not allowed. GetShort(int index)821*890232f2SAndroid Build Coastguard Worker public short GetShort(int index) 822*890232f2SAndroid Build Coastguard Worker { 823*890232f2SAndroid Build Coastguard Worker return (short)ReadLittleEndian(index, sizeof(short)); 824*890232f2SAndroid Build Coastguard Worker } 825*890232f2SAndroid Build Coastguard Worker GetUshort(int index)826*890232f2SAndroid Build Coastguard Worker public ushort GetUshort(int index) 827*890232f2SAndroid Build Coastguard Worker { 828*890232f2SAndroid Build Coastguard Worker return (ushort)ReadLittleEndian(index, sizeof(ushort)); 829*890232f2SAndroid Build Coastguard Worker } 830*890232f2SAndroid Build Coastguard Worker GetInt(int index)831*890232f2SAndroid Build Coastguard Worker public int GetInt(int index) 832*890232f2SAndroid Build Coastguard Worker { 833*890232f2SAndroid Build Coastguard Worker return (int)ReadLittleEndian(index, sizeof(int)); 834*890232f2SAndroid Build Coastguard Worker } 835*890232f2SAndroid Build Coastguard Worker GetUint(int index)836*890232f2SAndroid Build Coastguard Worker public uint GetUint(int index) 837*890232f2SAndroid Build Coastguard Worker { 838*890232f2SAndroid Build Coastguard Worker return (uint)ReadLittleEndian(index, sizeof(uint)); 839*890232f2SAndroid Build Coastguard Worker } 840*890232f2SAndroid Build Coastguard Worker GetLong(int index)841*890232f2SAndroid Build Coastguard Worker public long GetLong(int index) 842*890232f2SAndroid Build Coastguard Worker { 843*890232f2SAndroid Build Coastguard Worker return (long)ReadLittleEndian(index, sizeof(long)); 844*890232f2SAndroid Build Coastguard Worker } 845*890232f2SAndroid Build Coastguard Worker GetUlong(int index)846*890232f2SAndroid Build Coastguard Worker public ulong GetUlong(int index) 847*890232f2SAndroid Build Coastguard Worker { 848*890232f2SAndroid Build Coastguard Worker return ReadLittleEndian(index, sizeof(ulong)); 849*890232f2SAndroid Build Coastguard Worker } 850*890232f2SAndroid Build Coastguard Worker GetFloat(int index)851*890232f2SAndroid Build Coastguard Worker public float GetFloat(int index) 852*890232f2SAndroid Build Coastguard Worker { 853*890232f2SAndroid Build Coastguard Worker // TODO(derekbailey): use BitConvert.Int32BitsToSingle() whenever flatbuffers upgrades to a .NET version 854*890232f2SAndroid Build Coastguard Worker // that contains it. 855*890232f2SAndroid Build Coastguard Worker ConversionUnion union; 856*890232f2SAndroid Build Coastguard Worker union.floatValue = 0; 857*890232f2SAndroid Build Coastguard Worker union.intValue = (int)ReadLittleEndian(index, sizeof(float)); 858*890232f2SAndroid Build Coastguard Worker return union.floatValue; 859*890232f2SAndroid Build Coastguard Worker } 860*890232f2SAndroid Build Coastguard Worker GetDouble(int index)861*890232f2SAndroid Build Coastguard Worker public double GetDouble(int index) 862*890232f2SAndroid Build Coastguard Worker { 863*890232f2SAndroid Build Coastguard Worker return BitConverter.Int64BitsToDouble((long)ReadLittleEndian(index, sizeof(double))); 864*890232f2SAndroid Build Coastguard Worker } 865*890232f2SAndroid Build Coastguard Worker #endif // UNSAFE_BYTEBUFFER 866*890232f2SAndroid Build Coastguard Worker 867*890232f2SAndroid Build Coastguard Worker /// <summary> 868*890232f2SAndroid Build Coastguard Worker /// Copies an array of type T into this buffer, ending at the given 869*890232f2SAndroid Build Coastguard Worker /// offset into this buffer. The starting offset is calculated based on the length 870*890232f2SAndroid Build Coastguard Worker /// of the array and is the value returned. 871*890232f2SAndroid Build Coastguard Worker /// </summary> 872*890232f2SAndroid Build Coastguard Worker /// <typeparam name="T">The type of the input data (must be a struct)</typeparam> 873*890232f2SAndroid Build Coastguard Worker /// <param name="offset">The offset into this buffer where the copy will end</param> 874*890232f2SAndroid Build Coastguard Worker /// <param name="x">The array to copy data from</param> 875*890232f2SAndroid Build Coastguard Worker /// <returns>The 'start' location of this buffer now, after the copy completed</returns> 876*890232f2SAndroid Build Coastguard Worker public int Put<T>(int offset, T[] x) 877*890232f2SAndroid Build Coastguard Worker where T : struct 878*890232f2SAndroid Build Coastguard Worker { 879*890232f2SAndroid Build Coastguard Worker if (x == null) 880*890232f2SAndroid Build Coastguard Worker { 881*890232f2SAndroid Build Coastguard Worker throw new ArgumentNullException("Cannot put a null array"); 882*890232f2SAndroid Build Coastguard Worker } 883*890232f2SAndroid Build Coastguard Worker 884*890232f2SAndroid Build Coastguard Worker return Put(offset, new ArraySegment<T>(x)); 885*890232f2SAndroid Build Coastguard Worker } 886*890232f2SAndroid Build Coastguard Worker 887*890232f2SAndroid Build Coastguard Worker /// <summary> 888*890232f2SAndroid Build Coastguard Worker /// Copies an array segment of type T into this buffer, ending at the 889*890232f2SAndroid Build Coastguard Worker /// given offset into this buffer. The starting offset is calculated 890*890232f2SAndroid Build Coastguard Worker /// based on the count of the array segment and is the value returned. 891*890232f2SAndroid Build Coastguard Worker /// </summary> 892*890232f2SAndroid Build Coastguard Worker /// <typeparam name="T">The type of the input data (must be a struct) 893*890232f2SAndroid Build Coastguard Worker /// </typeparam> 894*890232f2SAndroid Build Coastguard Worker /// <param name="offset">The offset into this buffer where the copy 895*890232f2SAndroid Build Coastguard Worker /// will end</param> 896*890232f2SAndroid Build Coastguard Worker /// <param name="x">The array segment to copy data from</param> 897*890232f2SAndroid Build Coastguard Worker /// <returns>The 'start' location of this buffer now, after the copy 898*890232f2SAndroid Build Coastguard Worker /// completed</returns> 899*890232f2SAndroid Build Coastguard Worker public int Put<T>(int offset, ArraySegment<T> x) 900*890232f2SAndroid Build Coastguard Worker where T : struct 901*890232f2SAndroid Build Coastguard Worker { 902*890232f2SAndroid Build Coastguard Worker if (x.Equals(default(ArraySegment<T>))) 903*890232f2SAndroid Build Coastguard Worker { 904*890232f2SAndroid Build Coastguard Worker throw new ArgumentNullException("Cannot put a uninitialized array segment"); 905*890232f2SAndroid Build Coastguard Worker } 906*890232f2SAndroid Build Coastguard Worker 907*890232f2SAndroid Build Coastguard Worker if (x.Count == 0) 908*890232f2SAndroid Build Coastguard Worker { 909*890232f2SAndroid Build Coastguard Worker throw new ArgumentException("Cannot put an empty array"); 910*890232f2SAndroid Build Coastguard Worker } 911*890232f2SAndroid Build Coastguard Worker 912*890232f2SAndroid Build Coastguard Worker if (!IsSupportedType<T>()) 913*890232f2SAndroid Build Coastguard Worker { 914*890232f2SAndroid Build Coastguard Worker throw new ArgumentException("Cannot put an array of type " 915*890232f2SAndroid Build Coastguard Worker + typeof(T) + " into this buffer"); 916*890232f2SAndroid Build Coastguard Worker } 917*890232f2SAndroid Build Coastguard Worker 918*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 919*890232f2SAndroid Build Coastguard Worker { 920*890232f2SAndroid Build Coastguard Worker int numBytes = ByteBuffer.ArraySize(x); 921*890232f2SAndroid Build Coastguard Worker offset -= numBytes; 922*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, numBytes); 923*890232f2SAndroid Build Coastguard Worker // if we are LE, just do a block copy 924*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) 925*890232f2SAndroid Build Coastguard Worker MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes)); 926*890232f2SAndroid Build Coastguard Worker #else 927*890232f2SAndroid Build Coastguard Worker var srcOffset = ByteBuffer.SizeOf<T>() * x.Offset; 928*890232f2SAndroid Build Coastguard Worker Buffer.BlockCopy(x.Array, srcOffset, _buffer.Buffer, offset, numBytes); 929*890232f2SAndroid Build Coastguard Worker #endif 930*890232f2SAndroid Build Coastguard Worker } 931*890232f2SAndroid Build Coastguard Worker else 932*890232f2SAndroid Build Coastguard Worker { 933*890232f2SAndroid Build Coastguard Worker throw new NotImplementedException("Big Endian Support not implemented yet " + 934*890232f2SAndroid Build Coastguard Worker "for putting typed arrays"); 935*890232f2SAndroid Build Coastguard Worker // if we are BE, we have to swap each element by itself 936*890232f2SAndroid Build Coastguard Worker //for(int i = x.Length - 1; i >= 0; i--) 937*890232f2SAndroid Build Coastguard Worker //{ 938*890232f2SAndroid Build Coastguard Worker // todo: low priority, but need to genericize the Put<T>() functions 939*890232f2SAndroid Build Coastguard Worker //} 940*890232f2SAndroid Build Coastguard Worker } 941*890232f2SAndroid Build Coastguard Worker return offset; 942*890232f2SAndroid Build Coastguard Worker } 943*890232f2SAndroid Build Coastguard Worker 944*890232f2SAndroid Build Coastguard Worker /// <summary> 945*890232f2SAndroid Build Coastguard Worker /// Copies an array segment of type T into this buffer, ending at the 946*890232f2SAndroid Build Coastguard Worker /// given offset into this buffer. The starting offset is calculated 947*890232f2SAndroid Build Coastguard Worker /// based on the count of the array segment and is the value returned. 948*890232f2SAndroid Build Coastguard Worker /// </summary> 949*890232f2SAndroid Build Coastguard Worker /// <typeparam name="T">The type of the input data (must be a struct) 950*890232f2SAndroid Build Coastguard Worker /// </typeparam> 951*890232f2SAndroid Build Coastguard Worker /// <param name="offset">The offset into this buffer where the copy 952*890232f2SAndroid Build Coastguard Worker /// will end</param> 953*890232f2SAndroid Build Coastguard Worker /// <param name="ptr">The pointer to copy data from</param> 954*890232f2SAndroid Build Coastguard Worker /// <param name="sizeInBytes">The number of bytes to copy</param> 955*890232f2SAndroid Build Coastguard Worker /// <returns>The 'start' location of this buffer now, after the copy 956*890232f2SAndroid Build Coastguard Worker /// completed</returns> 957*890232f2SAndroid Build Coastguard Worker public int Put<T>(int offset, IntPtr ptr, int sizeInBytes) 958*890232f2SAndroid Build Coastguard Worker where T : struct 959*890232f2SAndroid Build Coastguard Worker { 960*890232f2SAndroid Build Coastguard Worker if (ptr == IntPtr.Zero) 961*890232f2SAndroid Build Coastguard Worker { 962*890232f2SAndroid Build Coastguard Worker throw new ArgumentNullException("Cannot add a null pointer"); 963*890232f2SAndroid Build Coastguard Worker } 964*890232f2SAndroid Build Coastguard Worker 965*890232f2SAndroid Build Coastguard Worker if(sizeInBytes <= 0) 966*890232f2SAndroid Build Coastguard Worker { 967*890232f2SAndroid Build Coastguard Worker throw new ArgumentException("Cannot put an empty array"); 968*890232f2SAndroid Build Coastguard Worker } 969*890232f2SAndroid Build Coastguard Worker 970*890232f2SAndroid Build Coastguard Worker if (!IsSupportedType<T>()) 971*890232f2SAndroid Build Coastguard Worker { 972*890232f2SAndroid Build Coastguard Worker throw new ArgumentException("Cannot put an array of type " 973*890232f2SAndroid Build Coastguard Worker + typeof(T) + " into this buffer"); 974*890232f2SAndroid Build Coastguard Worker } 975*890232f2SAndroid Build Coastguard Worker 976*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 977*890232f2SAndroid Build Coastguard Worker { 978*890232f2SAndroid Build Coastguard Worker offset -= sizeInBytes; 979*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, sizeInBytes); 980*890232f2SAndroid Build Coastguard Worker // if we are LE, just do a block copy 981*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && UNSAFE_BYTEBUFFER 982*890232f2SAndroid Build Coastguard Worker unsafe 983*890232f2SAndroid Build Coastguard Worker { 984*890232f2SAndroid Build Coastguard Worker var span = new Span<byte>(ptr.ToPointer(), sizeInBytes); 985*890232f2SAndroid Build Coastguard Worker span.CopyTo(_buffer.Span.Slice(offset, sizeInBytes)); 986*890232f2SAndroid Build Coastguard Worker } 987*890232f2SAndroid Build Coastguard Worker #else 988*890232f2SAndroid Build Coastguard Worker Marshal.Copy(ptr, _buffer.Buffer, offset, sizeInBytes); 989*890232f2SAndroid Build Coastguard Worker #endif 990*890232f2SAndroid Build Coastguard Worker } 991*890232f2SAndroid Build Coastguard Worker else 992*890232f2SAndroid Build Coastguard Worker { 993*890232f2SAndroid Build Coastguard Worker throw new NotImplementedException("Big Endian Support not implemented yet " + 994*890232f2SAndroid Build Coastguard Worker "for putting typed arrays"); 995*890232f2SAndroid Build Coastguard Worker // if we are BE, we have to swap each element by itself 996*890232f2SAndroid Build Coastguard Worker //for(int i = x.Length - 1; i >= 0; i--) 997*890232f2SAndroid Build Coastguard Worker //{ 998*890232f2SAndroid Build Coastguard Worker // todo: low priority, but need to genericize the Put<T>() functions 999*890232f2SAndroid Build Coastguard Worker //} 1000*890232f2SAndroid Build Coastguard Worker } 1001*890232f2SAndroid Build Coastguard Worker return offset; 1002*890232f2SAndroid Build Coastguard Worker } 1003*890232f2SAndroid Build Coastguard Worker 1004*890232f2SAndroid Build Coastguard Worker #if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1) 1005*890232f2SAndroid Build Coastguard Worker public int Put<T>(int offset, Span<T> x) 1006*890232f2SAndroid Build Coastguard Worker where T : struct 1007*890232f2SAndroid Build Coastguard Worker { 1008*890232f2SAndroid Build Coastguard Worker if (x.Length == 0) 1009*890232f2SAndroid Build Coastguard Worker { 1010*890232f2SAndroid Build Coastguard Worker throw new ArgumentException("Cannot put an empty array"); 1011*890232f2SAndroid Build Coastguard Worker } 1012*890232f2SAndroid Build Coastguard Worker 1013*890232f2SAndroid Build Coastguard Worker if (!IsSupportedType<T>()) 1014*890232f2SAndroid Build Coastguard Worker { 1015*890232f2SAndroid Build Coastguard Worker throw new ArgumentException("Cannot put an array of type " 1016*890232f2SAndroid Build Coastguard Worker + typeof(T) + " into this buffer"); 1017*890232f2SAndroid Build Coastguard Worker } 1018*890232f2SAndroid Build Coastguard Worker 1019*890232f2SAndroid Build Coastguard Worker if (BitConverter.IsLittleEndian) 1020*890232f2SAndroid Build Coastguard Worker { 1021*890232f2SAndroid Build Coastguard Worker int numBytes = ByteBuffer.ArraySize(x); 1022*890232f2SAndroid Build Coastguard Worker offset -= numBytes; 1023*890232f2SAndroid Build Coastguard Worker AssertOffsetAndLength(offset, numBytes); 1024*890232f2SAndroid Build Coastguard Worker // if we are LE, just do a block copy 1025*890232f2SAndroid Build Coastguard Worker MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes)); 1026*890232f2SAndroid Build Coastguard Worker } 1027*890232f2SAndroid Build Coastguard Worker else 1028*890232f2SAndroid Build Coastguard Worker { 1029*890232f2SAndroid Build Coastguard Worker throw new NotImplementedException("Big Endian Support not implemented yet " + 1030*890232f2SAndroid Build Coastguard Worker "for putting typed arrays"); 1031*890232f2SAndroid Build Coastguard Worker // if we are BE, we have to swap each element by itself 1032*890232f2SAndroid Build Coastguard Worker //for(int i = x.Length - 1; i >= 0; i--) 1033*890232f2SAndroid Build Coastguard Worker //{ 1034*890232f2SAndroid Build Coastguard Worker // todo: low priority, but need to genericize the Put<T>() functions 1035*890232f2SAndroid Build Coastguard Worker //} 1036*890232f2SAndroid Build Coastguard Worker } 1037*890232f2SAndroid Build Coastguard Worker return offset; 1038*890232f2SAndroid Build Coastguard Worker } 1039*890232f2SAndroid Build Coastguard Worker #endif 1040*890232f2SAndroid Build Coastguard Worker } 1041*890232f2SAndroid Build Coastguard Worker } 1042