123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809 |
- using System;
- using System.Diagnostics;
- using Unity.Collections.LowLevel.Unsafe;
- using UnityEngine.Scripting.APIUpdating;
-
- namespace Unity.Collections
- {
- /// <summary>
- /// Writes data in an endian format to deserialize data.
- /// </summary>
- /// <remarks>
- /// The DataStreamReader class is the counterpart of the
- /// <see cref="DataStreamWriter"/> class and can be be used to deserialize
- /// data which was prepared with it.
- ///
- /// DataStreamWriter writes this data in the endian format native
- /// to the current machine architecture.
- /// <br/>
- /// For network byte order use the so named methods.
- /// <br/>
- /// Simple usage example:
- /// <code>
- /// using (var dataWriter = new DataStreamWriter(16, Allocator.Persistent))
- /// {
- /// dataWriter.Write(42);
- /// dataWriter.Write(1234);
- /// // Length is the actual amount of data inside the writer,
- /// // Capacity is the total amount.
- /// var dataReader = new DataStreamReader(dataWriter, 0, dataWriter.Length);
- /// var context = default(DataStreamReader.Context);
- /// var myFirstInt = dataReader.ReadInt(ref context);
- /// var mySecondInt = dataReader.ReadInt(ref context);
- /// }
- /// </code>
- ///
- /// DataStreamReader carries the position of the read pointer inside the struct,
- /// taking a copy of the reader will also copy the read position. This includes passing the
- /// reader to a method by value instead of by ref.
- ///
- /// <seealso cref="DataStreamWriter"/>
- /// <seealso cref="IsLittleEndian"/>
- /// </remarks>
- [MovedFrom(true, "Unity.Networking.Transport")]
- [GenerateTestsForBurstCompatibility]
- public unsafe struct DataStreamReader
- {
- struct Context
- {
- public int m_ReadByteIndex;
- public int m_BitIndex;
- public ulong m_BitBuffer;
- public int m_FailedReads;
- }
-
- [NativeDisableUnsafePtrRestriction] internal byte* m_BufferPtr;
- Context m_Context;
- int m_Length;
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- AtomicSafetyHandle m_Safety;
- #endif
-
- /// <summary>
- /// Initializes a new instance of the DataStreamReader struct with a NativeArray<byte>
- /// </summary>
- /// <param name="array">The buffer to attach to the DataStreamReader.</param>
- public DataStreamReader(NativeArray<byte> array)
- {
- Initialize(out this, array);
- }
-
- static void Initialize(out DataStreamReader self, NativeArray<byte> array)
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- self.m_Safety = NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array);
- #endif
- self.m_BufferPtr = (byte*)array.GetUnsafeReadOnlyPtr();
- self.m_Length = array.Length;
- self.m_Context = default;
- }
-
- /// <summary>
- /// Show the byte order in which the current computer architecture stores data.
- /// </summary>
- /// <remarks>
- /// Different computer architectures store data using different byte orders.
- /// <list type="bullet">
- /// <item>Big-endian: the most significant byte is at the left end of a word.</item>
- /// <item>Little-endian: means the most significant byte is at the right end of a word.</item>
- /// </list>
- /// </remarks>
- public static bool IsLittleEndian { get { return DataStreamWriter.IsLittleEndian; } }
-
- static short ByteSwap(short val)
- {
- return (short)(((val & 0xff) << 8) | ((val >> 8) & 0xff));
- }
-
- static int ByteSwap(int val)
- {
- return (int)(((val & 0xff) << 24) | ((val & 0xff00) << 8) | ((val >> 8) & 0xff00) | ((val >> 24) & 0xff));
- }
-
- /// <summary>
- /// If there is a read failure this returns true. A read failure might happen if this attempts to read more than there is capacity for.
- /// </summary>
- public readonly bool HasFailedReads => m_Context.m_FailedReads > 0;
-
- /// <summary>
- /// The total size of the buffer space this reader is working with.
- /// </summary>
- public readonly int Length
- {
- get
- {
- CheckRead();
- return m_Length;
- }
- }
-
- /// <summary>
- /// True if the reader has been pointed to a valid buffer space. This
- /// would be false if the reader was created with no arguments.
- /// </summary>
- public readonly bool IsCreated
- {
- get { return m_BufferPtr != null; }
- }
-
- void ReadBytesInternal(byte* data, int length)
- {
- CheckRead();
- if (GetBytesRead() + length > m_Length)
- {
- ++m_Context.m_FailedReads;
- #if (ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG)
- UnityEngine.Debug.LogError($"Trying to read {length} bytes from a stream where only {m_Length - GetBytesRead()} are available");
- #endif
- UnsafeUtility.MemClear(data, length);
- return;
- }
- // Restore the full bytes moved to the bit buffer but no consumed
- m_Context.m_ReadByteIndex -= (m_Context.m_BitIndex >> 3);
- m_Context.m_BitIndex = 0;
- m_Context.m_BitBuffer = 0;
- UnsafeUtility.MemCpy(data, m_BufferPtr + m_Context.m_ReadByteIndex, length);
- m_Context.m_ReadByteIndex += length;
- }
-
- /// <summary>
- /// Read and copy data into the given NativeArray of bytes. An error will
- /// be logged if not enough bytes are available to fill the array, and
- /// <see cref="HasFailedReads"/> will then be true.
- /// </summary>
- /// <param name="array">Array to copy data into.</param>
- public void ReadBytes(NativeArray<byte> array)
- {
- ReadBytesInternal((byte*)array.GetUnsafePtr(), array.Length);
- }
-
- /// <summary>
- /// Read and copy data into the given <c>Span</c> of bytes. An error will
- /// be logged if not enough bytes are available to fill the array, and
- /// <see cref="HasFailedReads"/> will then be true.
- /// </summary>
- /// <param name="span">Span to copy data into.</param>
- public void ReadBytes(Span<byte> span)
- {
- fixed (byte* ptr = span)
- {
- ReadBytesInternal(ptr, span.Length);
- }
- }
-
- /// <summary>
- /// Gets the number of bytes read from the data stream.
- /// </summary>
- /// <returns>Number of bytes read.</returns>
- public int GetBytesRead()
- {
- return m_Context.m_ReadByteIndex - (m_Context.m_BitIndex >> 3);
- }
-
- /// <summary>
- /// Gets the number of bits read from the data stream.
- /// </summary>
- /// <returns>Number of bits read.</returns>
- public int GetBitsRead()
- {
- return (m_Context.m_ReadByteIndex << 3) - m_Context.m_BitIndex;
- }
-
- /// <summary>
- /// Sets the current position of this stream to the given value.
- /// An error will be logged if <paramref name="pos"/> is outside the length of the stream.
- /// <br/>
- /// In addition this will reset the bit index and the bit buffer.
- /// </summary>
- /// <param name="pos">Seek position.</param>
- public void SeekSet(int pos)
- {
- if (pos > m_Length)
- {
- ++m_Context.m_FailedReads;
- #if (ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG)
- UnityEngine.Debug.LogError($"Trying to seek to {pos} in a stream of length {m_Length}");
- #endif
- return;
- }
- m_Context.m_ReadByteIndex = pos;
- m_Context.m_BitIndex = 0;
- m_Context.m_BitBuffer = 0UL;
- }
-
- /// <summary>
- /// Reads an unsigned byte from the current stream and advances the current position of the stream by one byte.
- /// </summary>
- /// <returns>The next byte read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public byte ReadByte()
- {
- byte data;
- ReadBytesInternal((byte*)&data, sizeof(byte));
- return data;
- }
-
- /// <summary>
- /// Reads a 2-byte signed short from the current stream and advances the current position of the stream by two bytes.
- /// </summary>
- /// <returns>A 2-byte signed short read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public short ReadShort()
- {
- short data;
- ReadBytesInternal((byte*)&data, sizeof(short));
- return data;
- }
-
- /// <summary>
- /// Reads a 2-byte unsigned short from the current stream and advances the current position of the stream by two bytes.
- /// </summary>
- /// <returns>A 2-byte unsigned short read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public ushort ReadUShort()
- {
- ushort data;
- ReadBytesInternal((byte*)&data, sizeof(ushort));
- return data;
- }
-
- /// <summary>
- /// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four bytes.
- /// </summary>
- /// <returns>A 4-byte signed integer read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public int ReadInt()
- {
- int data;
- ReadBytesInternal((byte*)&data, sizeof(int));
- return data;
- }
-
- /// <summary>
- /// Reads a 4-byte unsigned integer from the current stream and advances the current position of the stream by four bytes.
- /// </summary>
- /// <returns>A 4-byte unsigned integer read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public uint ReadUInt()
- {
- uint data;
- ReadBytesInternal((byte*)&data, sizeof(uint));
- return data;
- }
-
- /// <summary>
- /// Reads an 8-byte signed long from the stream and advances the current position of the stream by eight bytes.
- /// </summary>
- /// <returns>An 8-byte signed long read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public long ReadLong()
- {
- long data;
- ReadBytesInternal((byte*)&data, sizeof(long));
- return data;
- }
-
- /// <summary>
- /// Reads an 8-byte unsigned long from the stream and advances the current position of the stream by eight bytes.
- /// </summary>
- /// <returns>An 8-byte unsigned long read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public ulong ReadULong()
- {
- ulong data;
- ReadBytesInternal((byte*)&data, sizeof(ulong));
- return data;
- }
-
- /// <summary>
- /// Reads a 2-byte signed short from the current stream in Big-endian byte order and advances the current position of the stream by two bytes.
- /// If the current endianness is in little-endian order, the byte order will be swapped.
- /// </summary>
- /// <returns>A 2-byte signed short read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public short ReadShortNetworkByteOrder()
- {
- short data;
- ReadBytesInternal((byte*)&data, sizeof(short));
- return IsLittleEndian ? ByteSwap(data) : data;
- }
-
- /// <summary>
- /// Reads a 2-byte unsigned short from the current stream in Big-endian byte order and advances the current position of the stream by two bytes.
- /// If the current endianness is in little-endian order, the byte order will be swapped.
- /// </summary>
- /// <returns>A 2-byte unsigned short read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public ushort ReadUShortNetworkByteOrder()
- {
- return (ushort)ReadShortNetworkByteOrder();
- }
-
- /// <summary>
- /// Reads a 4-byte signed integer from the current stream in Big-endian byte order and advances the current position of the stream by four bytes.
- /// If the current endianness is in little-endian order, the byte order will be swapped.
- /// </summary>
- /// <returns>A 4-byte signed integer read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public int ReadIntNetworkByteOrder()
- {
- int data;
- ReadBytesInternal((byte*)&data, sizeof(int));
- return IsLittleEndian ? ByteSwap(data) : data;
- }
-
- /// <summary>
- /// Reads a 4-byte unsigned integer from the current stream in Big-endian byte order and advances the current position of the stream by four bytes.
- /// If the current endianness is in little-endian order, the byte order will be swapped.
- /// </summary>
- /// <returns>A 4-byte unsigned integer read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public uint ReadUIntNetworkByteOrder()
- {
- return (uint)ReadIntNetworkByteOrder();
- }
-
- /// <summary>
- /// Reads a 4-byte floating point value from the current stream and advances the current position of the stream by four bytes.
- /// </summary>
- /// <returns>A 4-byte floating point value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public float ReadFloat()
- {
- UIntFloat uf = new UIntFloat();
- uf.intValue = (uint)ReadInt();
- return uf.floatValue;
- }
-
- /// <summary>
- /// Reads a 8-byte floating point value from the current stream and advances the current position of the stream by four bytes.
- /// </summary>
- /// <returns>A 8-byte floating point value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public double ReadDouble()
- {
- UIntFloat uf = new UIntFloat();
- uf.longValue = (ulong)ReadLong();
- return uf.doubleValue;
- }
-
- /// <summary>
- /// Reads a 4-byte unsigned integer from the current stream using a <see cref="StreamCompressionModel"/> and advances the current position the number of bits depending on the model.
- /// </summary>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>A 4-byte unsigned integer read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public uint ReadPackedUInt(in StreamCompressionModel model)
- {
- return ReadPackedUIntInternal(StreamCompressionModel.k_MaxHuffmanSymbolLength, model);
- }
-
- uint ReadPackedUIntInternal(int maxSymbolLength, in StreamCompressionModel model)
- {
- CheckRead();
- FillBitBuffer();
- uint peekMask = (1u << maxSymbolLength) - 1u;
- uint peekBits = (uint)m_Context.m_BitBuffer & peekMask;
- ushort huffmanEntry = model.decodeTable[(int)peekBits];
- int symbol = huffmanEntry >> 8;
- int length = huffmanEntry & 0xFF;
-
- if (m_Context.m_BitIndex < length)
- {
- ++m_Context.m_FailedReads;
- #if (ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG)
- UnityEngine.Debug.LogError($"Trying to read {length} bits from a stream where only {m_Context.m_BitIndex} are available");
- #endif
- return 0;
- }
-
- // Skip Huffman bits
- m_Context.m_BitBuffer >>= length;
- m_Context.m_BitIndex -= length;
-
- uint offset = model.bucketOffsets[symbol];
- byte bits = model.bucketSizes[symbol];
- return ReadRawBitsInternal(bits) + offset;
- }
-
- void FillBitBuffer()
- {
- while (m_Context.m_BitIndex <= 56 && m_Context.m_ReadByteIndex < m_Length)
- {
- m_Context.m_BitBuffer |= (ulong)m_BufferPtr[m_Context.m_ReadByteIndex++] << m_Context.m_BitIndex;
- m_Context.m_BitIndex += 8;
- }
- }
-
- uint ReadRawBitsInternal(int numbits)
- {
- CheckBits(numbits);
- if (m_Context.m_BitIndex < numbits)
- {
- ++m_Context.m_FailedReads;
- #if (ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG)
- UnityEngine.Debug.LogError($"Trying to read {numbits} bits from a stream where only {m_Context.m_BitIndex} are available");
- #endif
- return 0;
- }
- uint res = (uint)(m_Context.m_BitBuffer & ((1UL << numbits) - 1UL));
- m_Context.m_BitBuffer >>= numbits;
- m_Context.m_BitIndex -= numbits;
- return res;
- }
-
- /// <summary>
- /// Reads a specified number of bits from the data stream.
- /// </summary>
- /// <param name="numbits">A positive number of bytes to write.</param>
- /// <returns>A 4-byte unsigned integer read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public uint ReadRawBits(int numbits)
- {
- CheckRead();
- FillBitBuffer();
- return ReadRawBitsInternal(numbits);
- }
-
- /// <summary>
- /// Reads an 8-byte unsigned long value from the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>An 8-byte unsigned long read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public ulong ReadPackedULong(in StreamCompressionModel model)
- {
- ulong value;
- ((uint*)&value)[0] = ReadPackedUInt(model);
- ((uint*)&value)[1] = ReadPackedUInt(model);
- return value;
- }
-
- /// <summary>
- /// Reads a 4-byte signed integer value from the data stream using a <see cref="StreamCompressionModel"/>.
- /// <br/>
- /// Negative values de-interleaves from positive values before returning, for example (0, -1, 1, -2, 2) -> (-2, -1, 0, 1, 2)
- /// </summary>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>A 4-byte signed integer read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public int ReadPackedInt(in StreamCompressionModel model)
- {
- uint folded = ReadPackedUInt(model);
- return (int)(folded >> 1) ^ -(int)(folded & 1); // Deinterleave values from [0, -1, 1, -2, 2...] to [..., -2, -1, -0, 1, 2, ...]
- }
-
- /// <summary>
- /// Reads an 8-byte signed long value from the data stream using a <see cref="StreamCompressionModel"/>.
- /// <br/>
- /// Negative values de-interleaves from positive values before returning, for example (0, -1, 1, -2, 2) -> (-2, -1, 0, 1, 2)
- /// </summary>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>An 8-byte signed long read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public long ReadPackedLong(in StreamCompressionModel model)
- {
- ulong folded = ReadPackedULong(model);
- return (long)(folded >> 1) ^ -(long)(folded & 1); // Deinterleave values from [0, -1, 1, -2, 2...] to [..., -2, -1, -0, 1, 2, ...]
- }
-
- /// <summary>
- /// Reads a 4-byte floating point value from the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>A 4-byte floating point value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public float ReadPackedFloat(in StreamCompressionModel model)
- {
- return ReadPackedFloatDelta(0, model);
- }
-
- /// <summary>
- /// Reads a 8-byte floating point value from the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>A 8-byte floating point value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public double ReadPackedDouble(in StreamCompressionModel model)
- {
- return ReadPackedDoubleDelta(0, model);
- }
-
- /// <summary>
- /// Reads a 4-byte signed integer delta value from the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="baseline">The previous 4-byte signed integer value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>A 4-byte signed integer read from the current stream, or 0 if the end of the stream has been reached.
- /// If the data did not change, this also returns 0.
- /// <br/>
- /// See: <see cref="HasFailedReads"/> to verify if the read failed.</returns>
- public int ReadPackedIntDelta(int baseline, in StreamCompressionModel model)
- {
- int delta = ReadPackedInt(model);
- return baseline - delta;
- }
-
- /// <summary>
- /// Reads a 4-byte unsigned integer delta value from the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="baseline">The previous 4-byte unsigned integer value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>A 4-byte unsigned integer read from the current stream, or 0 if the end of the stream has been reached.
- /// If the data did not change, this also returns 0.
- /// <br/>
- /// See: <see cref="HasFailedReads"/> to verify if the read failed.</returns>
- public uint ReadPackedUIntDelta(uint baseline, in StreamCompressionModel model)
- {
- uint delta = (uint)ReadPackedInt(model);
- return baseline - delta;
- }
-
- /// <summary>
- /// Reads an 8-byte signed long delta value from the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="baseline">The previous 8-byte signed long value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>An 8-byte signed long read from the current stream, or 0 if the end of the stream has been reached.
- /// If the data did not change, this also returns 0.
- /// <br/>
- /// See: <see cref="HasFailedReads"/> to verify if the read failed.</returns>
- public long ReadPackedLongDelta(long baseline, in StreamCompressionModel model)
- {
- long delta = ReadPackedLong(model);
- return baseline - delta;
- }
-
- /// <summary>
- /// Reads an 8-byte unsigned long delta value from the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="baseline">The previous 8-byte unsigned long value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for reading value in a packed manner.</param>
- /// <returns>An 8-byte unsigned long read from the current stream, or 0 if the end of the stream has been reached.
- /// If the data did not change, this also returns 0.
- /// <br/>
- /// See: <see cref="HasFailedReads"/> to verify if the read failed.</returns>
- public ulong ReadPackedULongDelta(ulong baseline, in StreamCompressionModel model)
- {
- ulong delta = (ulong)ReadPackedLong(model);
- return baseline - delta;
- }
-
- /// <summary>
- /// Reads a 4-byte floating point value from the data stream.
- ///
- /// If the first bit is 0, the data did not change and <paramref name="baseline"/> will be returned.
- /// </summary>
- /// <param name="baseline">The previous 4-byte floating point value.</param>
- /// <param name="model">Not currently used.</param>
- /// <returns>A 4-byte floating point value read from the current stream, or <paramref name="baseline"/> if there are no changes to the value.
- /// <br/>
- /// See: <see cref="HasFailedReads"/> to verify if the read failed.</returns>
- public float ReadPackedFloatDelta(float baseline, in StreamCompressionModel model)
- {
- CheckRead();
- FillBitBuffer();
- if (ReadRawBitsInternal(1) == 0)
- return baseline;
-
- var bits = 32;
- UIntFloat uf = new UIntFloat();
- uf.intValue = ReadRawBitsInternal(bits);
- return uf.floatValue;
- }
-
- /// <summary>
- /// Reads a 8-byte floating point value from the data stream.
- ///
- /// If the first bit is 0, the data did not change and <paramref name="baseline"/> will be returned.
- /// </summary>
- /// <param name="baseline">The previous 8-byte floating point value.</param>
- /// <param name="model">Not currently used.</param>
- /// <returns>A 8-byte floating point value read from the current stream, or <paramref name="baseline"/> if there are no changes to the value.
- /// <br/>
- /// See: <see cref="HasFailedReads"/> to verify if the read failed.</returns>
- public double ReadPackedDoubleDelta(double baseline, in StreamCompressionModel model)
- {
- CheckRead();
- FillBitBuffer();
- if (ReadRawBitsInternal(1) == 0)
- return baseline;
-
- var bits = 32;
- UIntFloat uf = new UIntFloat();
- var data = (uint*)&uf.longValue;
- data[0] = ReadRawBitsInternal(bits);
- FillBitBuffer();
- data[1] |= ReadRawBitsInternal(bits);
- return uf.doubleValue;
- }
-
- /// <summary>
- /// Reads a <c>FixedString32Bytes</c> value from the current stream and advances the current position of the stream by the length of the string.
- /// </summary>
- /// <returns>A <c>FixedString32Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString32Bytes ReadFixedString32()
- {
- FixedString32Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadFixedStringInternal(data, str.Capacity);
- return str;
- }
-
- /// <summary>
- /// Reads a <c>FixedString64Bytes</c> value from the current stream and advances the current position of the stream by the length of the string.
- /// </summary>
- /// <returns>A <c>FixedString64Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString64Bytes ReadFixedString64()
- {
- FixedString64Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadFixedStringInternal(data, str.Capacity);
- return str;
- }
-
- /// <summary>
- /// Reads a <c>FixedString128Bytes</c> value from the current stream and advances the current position of the stream by the length of the string.
- /// </summary>
- /// <returns>A <c>FixedString128Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString128Bytes ReadFixedString128()
- {
- FixedString128Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadFixedStringInternal(data, str.Capacity);
- return str;
- }
-
- /// <summary>
- /// Reads a <c>FixedString512Bytes</c> value from the current stream and advances the current position of the stream by the length of the string.
- /// </summary>
- /// <returns>A <c>FixedString512Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString512Bytes ReadFixedString512()
- {
- FixedString512Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadFixedStringInternal(data, str.Capacity);
- return str;
- }
-
- /// <summary>
- /// Reads a <c>FixedString4096Bytes</c> value from the current stream and advances the current position of the stream by the length of the string.
- /// </summary>
- /// <returns>A <c>FixedString4096Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString4096Bytes ReadFixedString4096()
- {
- FixedString4096Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadFixedStringInternal(data, str.Capacity);
- return str;
- }
-
- /// <summary>
- /// Read and copy data into the given NativeArray of bytes, an error will
- /// be logged if not enough bytes are available in the array.
- /// </summary>
- /// <param name="array">Buffer to write the string bytes to.</param>
- /// <returns>Length of data read into byte array, or zero if error occurred.</returns>
- public ushort ReadFixedString(NativeArray<byte> array)
- {
- return ReadFixedStringInternal((byte*)array.GetUnsafePtr(), array.Length);
- }
-
- unsafe ushort ReadFixedStringInternal(byte* data, int maxLength)
- {
- ushort length = ReadUShort();
- if (length > maxLength)
- {
- #if (ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG)
- UnityEngine.Debug.LogError($"Trying to read a string of length {length} but max length is {maxLength}");
- #endif
- return 0;
- }
- ReadBytesInternal(data, length);
- return length;
- }
-
- /// <summary>
- /// Reads a <c>FixedString32Bytes</c> delta value to the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="baseline">The previous <c>FixedString32Bytes</c> value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for writing value in a packed manner.</param>
- /// <returns>A <c>FixedString32Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString32Bytes ReadPackedFixedString32Delta(FixedString32Bytes baseline, in StreamCompressionModel model)
- {
- FixedString32Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadPackedFixedStringDeltaInternal(data, str.Capacity, ((byte*)&baseline) + 2, *((ushort*)&baseline), model);
- return str;
- }
-
- /// <summary>
- /// Reads a <c>FixedString64Bytes</c> delta value to the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="baseline">The previous <c>FixedString64Bytes</c> value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for writing value in a packed manner.</param>
- /// <returns>A <c>FixedString64Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString64Bytes ReadPackedFixedString64Delta(FixedString64Bytes baseline, in StreamCompressionModel model)
- {
- FixedString64Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadPackedFixedStringDeltaInternal(data, str.Capacity, ((byte*)&baseline) + 2, *((ushort*)&baseline), model);
- return str;
- }
-
- /// <summary>
- /// Reads a <c>FixedString128Bytes</c> delta value to the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="baseline">The previous <c>FixedString128Bytes</c> value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for writing value in a packed manner.</param>
- /// <returns>A <c>FixedString128Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString128Bytes ReadPackedFixedString128Delta(FixedString128Bytes baseline, in StreamCompressionModel model)
- {
- FixedString128Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadPackedFixedStringDeltaInternal(data, str.Capacity, ((byte*)&baseline) + 2, *((ushort*)&baseline), model);
- return str;
- }
-
- /// <summary>
- /// Reads a <c>FixedString512Bytes</c> delta value to the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="baseline">The previous <c>FixedString512Bytes</c> value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for writing value in a packed manner.</param>
- /// <returns>A <c>FixedString512Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString512Bytes ReadPackedFixedString512Delta(FixedString512Bytes baseline, in StreamCompressionModel model)
- {
- FixedString512Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadPackedFixedStringDeltaInternal(data, str.Capacity, ((byte*)&baseline) + 2, *((ushort*)&baseline), model);
- return str;
- }
-
- /// <summary>
- /// Reads a <c>FixedString4096Bytes</c> delta value to the data stream using a <see cref="StreamCompressionModel"/>.
- /// </summary>
- /// <param name="baseline">The previous <c>FixedString4096Bytes</c> value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for writing value in a packed manner.</param>
- /// <returns>A <c>FixedString4096Bytes</c> value read from the current stream, or 0 if the end of the stream has been reached.</returns>
- public unsafe FixedString4096Bytes ReadPackedFixedString4096Delta(FixedString4096Bytes baseline, in StreamCompressionModel model)
- {
- FixedString4096Bytes str;
- byte* data = ((byte*)&str) + 2;
- *(ushort*)&str = ReadPackedFixedStringDeltaInternal(data, str.Capacity, ((byte*)&baseline) + 2, *((ushort*)&baseline), model);
- return str;
- }
-
- /// <summary>
- /// Read and copy data into the given NativeArray of bytes, an error will
- /// be logged if not enough bytes are available in the array.
- /// </summary>
- /// <param name="data">Array for the current fixed string.</param>
- /// <param name="baseData">Array containing the previous value, used to compute the diff.</param>
- /// <param name="model"><see cref="StreamCompressionModel"/> model for writing value in a packed manner.</param>
- /// <returns>Length of data read into byte array, or zero if error occurred.</returns>
- public ushort ReadPackedFixedStringDelta(NativeArray<byte> data, NativeArray<byte> baseData, in StreamCompressionModel model)
- {
- return ReadPackedFixedStringDeltaInternal((byte*)data.GetUnsafePtr(), data.Length, (byte*)baseData.GetUnsafePtr(), (ushort)baseData.Length, model);
- }
-
- unsafe ushort ReadPackedFixedStringDeltaInternal(byte* data, int maxLength, byte* baseData, ushort baseLength, in StreamCompressionModel model)
- {
- uint length = ReadPackedUIntDelta(baseLength, model);
- if (length > (uint)maxLength)
- {
- #if (ENABLE_UNITY_COLLECTIONS_CHECKS || UNITY_DOTS_DEBUG)
- UnityEngine.Debug.LogError($"Trying to read a string of length {length} but max length is {maxLength}");
- #endif
- return 0;
- }
- if (length <= baseLength)
- {
- for (int i = 0; i < length; ++i)
- data[i] = (byte)ReadPackedUIntDelta(baseData[i], model);
- }
- else
- {
- for (int i = 0; i < baseLength; ++i)
- data[i] = (byte)ReadPackedUIntDelta(baseData[i], model);
- for (int i = baseLength; i < length; ++i)
- data[i] = (byte)ReadPackedUInt(model);
- }
- return (ushort)length;
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- internal readonly void CheckRead()
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
- #endif
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
- static void CheckBits(int numbits)
- {
- if (numbits < 0 || numbits > 32)
- throw new ArgumentOutOfRangeException("Invalid number of bits");
- }
- }
- }
|