Skip to content

Commit

Permalink
Svelto.Common 3.4.3
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastiano Mandala committed May 1, 2023
1 parent b3b6ad7 commit 409d48a
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 67 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# Changelog
All notable changes to this project will be documented in this file. Changes are listed in random order of importance.

## [3.4.3] - 05-2023

* fix platform profiler compilation bugs
* Svelto.Console improvements
* Improve the new stream related classes. They are used successfully in my current project, unfortunately no much doc available yet
* few FasterList improvements

## [3.4.0] - 03-2023

* removed static caches used in performance critical paths as they were causing unexpected performance issues (the fetching of static data is slower than i imagined)
Expand Down
18 changes: 14 additions & 4 deletions DataStructures/Arrays/FasterList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,22 @@ public FasterList(params T[] collection)
_count = (uint)collection.Length;
}

public FasterList(T[] collection, uint actualSize)
public FasterList(in ArraySegment<T> collection)
{
_buffer = new T[actualSize];
Array.Copy(collection, _buffer, actualSize);
_buffer = new T[collection.Count];

collection.CopyTo(_buffer, 0);

_count = actualSize;
_count = (uint)collection.Count;
}

public FasterList(in Span<T> collection)
{
_buffer = new T[collection.Length];

collection.CopyTo(_buffer);

_count = (uint)collection.Length;
}

public FasterList(ICollection<T> collection)
Expand Down
11 changes: 11 additions & 0 deletions DataStructures/Arrays/FasterListExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ public static class FasterListExtension
Span<byte> span = MemoryMarshal.AsBytes(spanT);
return span;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> ToSpan<T>(this FasterList<T> list) where T : unmanaged
{
T[] array = list.ToArrayFast(out var count);

Span<T> spanT = array.AsSpan(0, count);

return spanT;
}

#if IF_THE_OTHER_SOLUTION_FAILS
internal readonly ref struct DisposableHandle
{
Expand Down
15 changes: 5 additions & 10 deletions DataStructures/Streams/ByteArraySegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,16 @@ namespace Svelto.DataStructures
{
public readonly struct ByteArraySegment<T> where T : unmanaged
{
public ByteArraySegment(byte[] reference, int offsetInBytes, int sizeInBytes): this()
public ByteArraySegment(Memory<byte> reference): this()
{
_byteReference = new Memory<byte>(reference, offsetInBytes, sizeInBytes);
_byteReference = reference;
}

ByteArraySegment(T[] reference): this()
public ByteArraySegment(T[] reference): this()
{
_reference = reference;
}

public static implicit operator ByteArraySegment<T>(T[] list)
{
return new ByteArraySegment<T>(list);
}

public static implicit operator ReadOnlySpan<T>(in ByteArraySegment<T> list)
{
return list.Span;
Expand All @@ -44,9 +39,9 @@ public static class ByteArraySegmentExtension
{
int length = stream.Read<int>();

int readCursor = (int)stream.AdvanceCursor(length);
int readCursor = stream.AdvanceCursor(length);

return new ByteArraySegment<T>(stream.ToPTR(), readCursor, length);
return new ByteArraySegment<T>(stream.ToMemoryInternal().Slice(readCursor, length));
}
}
}
Expand Down
73 changes: 62 additions & 11 deletions DataStructures/Streams/ManagedStream.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,73 @@
#if NEW_C_SHARP || !UNITY_5_3_OR_NEWER
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Svelto.DataStructures
{
public struct ManagedStream
{
public ManagedStream(byte[] ptr, int sizeInByte):this()
public ManagedStream(byte[] ptr, int capacity):this()
{
_ptr = ptr;
_sveltoStream = new SveltoStream(sizeInByte);
_sveltoStream = new SveltoStream(capacity);
_offset = 0;
}

public ManagedStream(ArraySegment<byte> updateMessage)
{
_ptr = updateMessage.Array;
_sveltoStream = new SveltoStream(updateMessage.Count);
_offset = updateMessage.Offset;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Read<T>() where T : unmanaged => _sveltoStream.Read<T>(ToSpan());
public T Read<T>() where T : unmanaged => _sveltoStream.Read<T>(ToSpanInternal());

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Read<T>(in T item) where T : unmanaged => _sveltoStream.Read<T>(ToSpan());
public T Read<T>(in T item) where T : unmanaged => _sveltoStream.Read<T>(ToSpanInternal());

[MethodImpl(MethodImplOptions.AggressiveInlining)]
//T can contain managed elements, it's up to the user to be sure that the right data is read
public void UnsafeRead<T>(ref T item, int size) where T:struct => _sveltoStream.UnsafeRead(ref item, ToSpan(), size);
public void UnsafeRead<T>(ref T item, int unmanagedStructSize) where T:struct => _sveltoStream.UnsafeRead(ref item, ToSpanInternal(), unmanagedStructSize);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> ReadSpan<T>() where T : unmanaged //todo move this into SveltoStream
{
int length = Read<int>();

if (length > 0)
{
int readCursor = AdvanceCursor(length);

Span<byte> span = ToSpanInternal().Slice(readCursor, length);
return MemoryMarshal.Cast<byte, T>(span);
}

return Span<T>.Empty;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Write<T>(in T value) where T : unmanaged => _sveltoStream.Write(ToSpan(), value);
public ArraySegment<byte> ReadAsByteArray<T>() where T : unmanaged //todo move this into SveltoStream
{
int length = Read<int>();

if (length > 0)
{
int readCursor = AdvanceCursor(length);

ArraySegment<byte> span = new ArraySegment<byte>(_ptr, _offset, _sveltoStream.capacity).Slice(readCursor, length);
return span;
}

return new ArraySegment<byte>();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Write<T>(in Span<T> valueSpan) where T : unmanaged => _sveltoStream.WriteSpan(ToSpan(), valueSpan);
public void Write<T>(in T value) where T : unmanaged => _sveltoStream.Write(ToSpanInternal(), value);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteSpan<T>(in Span<T> valueSpan) where T : unmanaged => _sveltoStream.WriteSpan(ToSpanInternal(), valueSpan);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear() => _sveltoStream.Clear();
Expand All @@ -36,19 +77,29 @@ public ManagedStream(byte[] ptr, int sizeInByte):this()

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool CanAdvance() => _sveltoStream.CanAdvance();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<byte> ToSpan() => _ptr;
public bool CanAdvance<T>() where T : unmanaged => _sveltoStream.CanAdvance<T>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int AdvanceCursor(int sizeOf) => _sveltoStream.AdvanceCursor(sizeOf);
public Span<byte> ToSpan() => new(_ptr, _offset, _sveltoStream.count); //returns what has been written so far in the buffer

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Memory<byte> ToMemory() => new(_ptr, _offset, _sveltoStream.count); //returns what has been written so far in the buffer

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte[] ToPTR() => _ptr;
internal Memory<byte> ToMemoryInternal() => new(_ptr, _offset, _sveltoStream.capacity); //

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Span<byte> ToSpanInternal() => new(_ptr, _offset, _sveltoStream.capacity);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int AdvanceCursor(int sizeOf) => _sveltoStream.AdvanceCursor(sizeOf);

SveltoStream _sveltoStream; //CANNOT BE READ ONLY

readonly byte[] _ptr;
readonly int _offset;
}
}
#endif
53 changes: 50 additions & 3 deletions DataStructures/Streams/ManagerVOSerializationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,61 @@

namespace Svelto.DataStructures
{
/// <summary>
/// ManagedVO, which are VOs with arrays, use a more complicated pattern as they cannot be blitted as they are
/// the ISerializableManagedVO helps computing the actual size of the VO, including the arrays.
/// more tricks are used to speed up serialization: the Sequential and Packed 1 layout helps to serialise
/// the unmanaged part of the struct that must always stay at the beginning of the struct.
/// _constSize is used to compute the size of the unmanaged part of the struct, which is always the same.
/// the rest of the struct is serialised using the UnmanagedStream interface
/// example:
/// [StructLayout(LayoutKind.Sequential, Pack = 1)] //important otherwise the serialization trick for managed VOs won't work
/// public struct ProjectileBouncingEffectVO : ISerializableManagedVO
/// {
/// public UniqueId id;
/// public HashId effect_hash;
/// public UniqueId caster_id;
///
/// public UniqueId source_id;
/// public float source_x;
/// public float source_z;
///
/// public float anim_scale;
///
/// // Bouncing projectiles have a duration that is all the hit times added together
/// public float duration;
///
/// //in order to keep serialization code minimal, managed stuff must stay at the end of the declaration
/// public ByteArraySegment<float> hit_times;
/// public ByteArraySegment<long> hit_target_ids;
/// }
///
/// ByteArraySegment is also provided by Svelto.Common and must be used to serialise arrays (of unmanaged types)
///
/// </summary>
public interface ISerializableManagedVO
{
int SerializationSize();
void Serialize(ref UnmanagedStream stream);
}

public static class ManagerVOSerializationHelper
{
//this can be used like:
// FasterList<ProjectileBouncingEffectVO> bouncingProjectileEffectsBuffer = _valueObjectSystem.GetBouncingProjectileEffects();
// if (bouncingProjectileEffectsBuffer.count > 0)
// {
// using (platformProfiler.Sample("effects_proj_bounce serialization"))
// {
// unsafe
// {
// int serializeSize = bouncingProjectileEffectsBuffer.SerializeSize();
// byte* span = stackalloc byte[serializeSize]; //stack allocation
// var serializedVOs = new UnmanagedStream(span, serializeSize);
// realmVO.effects_proj_bounce = (bouncingProjectileEffectsBuffer.Serialize(ref serializedVOs));
// }
// }
// }
public static Span<byte> Serialize<T>(this FasterList<T> elements,
ref UnmanagedStream buffer) where T:ISerializableManagedVO
{
Expand All @@ -38,11 +85,11 @@ public static class ManagerVOSerializationHelper

return 0;
}

public static int SerializeSize<T>(this in ByteArraySegment<T> elements) where T:unmanaged
{
var length = elements.Span.Length;

if (length > 0)
{
var elementsLength = (length * MemoryUtilities.SizeOf<T>()) + sizeof(int);
Expand Down
32 changes: 24 additions & 8 deletions DataStructures/Streams/SveltoStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ public SveltoStream(int sizeInByte): this()
#endif
Unsafe.CopyBlockUnaligned(
ref Unsafe.As<T, byte>(ref item),
ref Unsafe.Add(ref MemoryMarshal.GetReference(source), _readCursor),
ref Unsafe.Add(ref MemoryMarshal.GetReference(source), _readCursor),
(uint)size); //size is not the size of T

_readCursor += size;
}

Expand Down Expand Up @@ -94,11 +94,14 @@ public SveltoStream(int sizeInByte): this()
if (space < spanBytesToSerialise)
throw new Exception("no writing authorized");
#endif
//create a local span of the destination from the right offset.
var destination = destinationSpan.Slice(_writeCursor, spanBytesToSerialise);
valueSpan.CopyTo(MemoryMarshal.Cast<byte, T>(destination));

_writeCursor += spanBytesToSerialise;
if (spanBytesToSerialise > 0)
{
//create a local span of the destination from the right offset.
var destination = destinationSpan.Slice(_writeCursor, spanBytesToSerialise);
valueSpan.CopyTo(MemoryMarshal.Cast<byte, T>(destination));

_writeCursor += spanBytesToSerialise;
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -113,7 +116,20 @@ public void Reset()
_readCursor = 0;
}

public bool CanAdvance() => _readCursor < capacity;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool CanAdvance()
{
return _readCursor < capacity;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool CanAdvance<T>()
where T : unmanaged
{
int elementSize = MemoryUtilities.SizeOf<T>();

return _readCursor + elementSize < capacity;
}

public int AdvanceCursor(int sizeOf)
{
Expand Down
19 changes: 14 additions & 5 deletions DataStructures/Streams/UnmanagedStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ public unsafe UnmanagedStream(byte* ptr, int sizeInByte):this()
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Read<T>() where T : unmanaged => _sveltoStream.Read<T>(ToSpan());
public T Read<T>() where T : unmanaged => _sveltoStream.Read<T>(ToSpanInternal());

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Write<T>(in T value) where T : unmanaged => _sveltoStream.Write(ToSpan(), value);
public void Write<T>(in T value) where T : unmanaged => _sveltoStream.Write(ToSpanInternal(), value);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
//T can contain managed elements, it's up to the user to be sure that the right data is read
public void UnsafeWrite<T>(in T value, int size) where T : struct => _sveltoStream.UnsafeWrite(ToSpan(), value, size);
public void UnsafeWrite<T>(in T value, int unmanagedStructSize) where T : struct => _sveltoStream.UnsafeWrite(ToSpanInternal(), value, unmanagedStructSize);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Write<T>(in Span<T> valueSpan) where T : unmanaged => _sveltoStream.WriteSpan(ToSpan(), valueSpan);
public void WriteSpan<T>(in Span<T> valueSpan) where T : unmanaged => _sveltoStream.WriteSpan(ToSpanInternal(), valueSpan);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear() => _sveltoStream.Clear();
Expand All @@ -35,7 +35,16 @@ public unsafe UnmanagedStream(byte* ptr, int sizeInByte):this()
public bool CanAdvance() => _sveltoStream.CanAdvance();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<byte> ToSpan()
public Span<byte> ToSpan() //returns what has been written so far in the buffer
{
unsafe
{
return new Span<byte>(_ptr, _sveltoStream.count);
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Span<byte> ToSpanInternal()
{
unsafe
{
Expand Down

0 comments on commit 409d48a

Please sign in to comment.