From f26c7293a492bc74c9f23f1ff823f09b21c344c3 Mon Sep 17 00:00:00 2001 From: Lars Date: Wed, 17 Apr 2024 22:55:50 +0200 Subject: [PATCH] Updated to CommunityToolkit 8.2.2 and added Ref and ReadOnlyRef for .NetStandard2.1 --- src/Arch.SourceGen/QueryGenerator.cs | 1 + src/Arch/Arch.csproj | 5 +- src/Arch/Core/Chunk.cs | 3 +- src/Arch/Core/Enumerators.cs | 1 + src/Arch/Core/Utils/ReadOnlyRef.cs | 71 ++++++++++++++++++++++++++++ src/Arch/Core/Utils/Ref.cs | 56 ++++++++++++++++++++++ 6 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 src/Arch/Core/Utils/ReadOnlyRef.cs create mode 100644 src/Arch/Core/Utils/Ref.cs diff --git a/src/Arch.SourceGen/QueryGenerator.cs b/src/Arch.SourceGen/QueryGenerator.cs index 3c4ea85d..68425ec8 100644 --- a/src/Arch.SourceGen/QueryGenerator.cs +++ b/src/Arch.SourceGen/QueryGenerator.cs @@ -39,6 +39,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) references.AppendLine("using System;"); references.AppendLine("using System.Runtime.CompilerServices;"); references.AppendLine("using CommunityToolkit.HighPerformance;"); + references.AppendLine("using Arch.Core.Utils;"); references.AppendLine("namespace Arch.Core;"); references.AppendComponents(25); references.AppendEntityComponents(25); diff --git a/src/Arch/Arch.csproj b/src/Arch/Arch.csproj index d5a50142..73e2fac2 100644 --- a/src/Arch/Arch.csproj +++ b/src/Arch/Arch.csproj @@ -29,8 +29,7 @@ Added World.IsAlive(EntityReference); Fixed bug where `World.TrimExcess` does not trim Recycled-Entities which results in an out of bounds exception sooner or later. Fixed bug in JobScheduler which prevents a deadlock. Moved CommandBuffer to Buffer namespace, might break references. -CommandBuffer now accepts a world during playback, world in ctor was removed. -CommandBuffer now triggers OnComponentRemoved events. +CommandBuffer now accepts a world during playback, world in ctor was removed. c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system;stride;unity;godot; https://github.com/genaray/Arch @@ -103,7 +102,7 @@ CommandBuffer now triggers OnComponentRemoved events. - + diff --git a/src/Arch/Core/Chunk.cs b/src/Arch/Core/Chunk.cs index ce0b2621..69ed9d70 100644 --- a/src/Arch/Core/Chunk.cs +++ b/src/Arch/Core/Chunk.cs @@ -256,7 +256,7 @@ public T[] GetArray() { var index = Index(); Debug.Assert(index != -1 && index < Components.Length, $"Index is out of bounds, component {typeof(T)} with id {index} does not exist in this chunk."); - ref var array = ref Components.DangerousGetReferenceAt(index); + var array = Components.DangerousGetReferenceAt(index); return Unsafe.As(array); } @@ -288,7 +288,6 @@ public ref T GetFirst() public partial struct Chunk { - /// /// Sets or replaces a component for an index in the chunk. /// This won't fire an event for . diff --git a/src/Arch/Core/Enumerators.cs b/src/Arch/Core/Enumerators.cs index 3977b879..2b72ef7e 100644 --- a/src/Arch/Core/Enumerators.cs +++ b/src/Arch/Core/Enumerators.cs @@ -1,4 +1,5 @@ using Arch.Core.Extensions.Internal; +using Arch.Core.Utils; using CommunityToolkit.HighPerformance; namespace Arch.Core; diff --git a/src/Arch/Core/Utils/ReadOnlyRef.cs b/src/Arch/Core/Utils/ReadOnlyRef.cs new file mode 100644 index 00000000..4557d416 --- /dev/null +++ b/src/Arch/Core/Utils/ReadOnlyRef.cs @@ -0,0 +1,71 @@ +using CommunityToolkit.HighPerformance.Helpers; + +namespace Arch.Core.Utils; + +#if NETSTANDARD2_1_OR_GREATER || NET6_0 + +/// +/// The struct +/// can store a readonly reference to a value of a specified type. +/// +/// The type of value to reference. +public readonly ref struct ReadOnlyRef +{ + /// + /// The 1-length instance used to track the target value. + /// + internal readonly ReadOnlySpan Span; + + /// + /// Initializes a new instance of the struct. + /// + /// The readonly reference to the target value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlyRef(in T value) + { + ref T r0 = ref Unsafe.AsRef(value); + + this.Span = MemoryMarshal.CreateReadOnlySpan(ref r0, 1); + } + + /// + /// Initializes a new instance of the struct. + /// + /// The pointer to the target value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe ReadOnlyRef(void* pointer) + : this(in Unsafe.AsRef(pointer)) + { + } + + /// + /// Gets the readonly reference represented by the current instance. + /// + public ref readonly T Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref MemoryMarshal.GetReference(this.Span); + } + + /// + /// Implicitly converts a instance into a one. + /// + /// The input instance. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlyRef(Ref reference) + { + return new(in reference.Value); + } + + /// + /// Implicitly gets the value from a given instance. + /// + /// The input instance. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator T(ReadOnlyRef reference) + { + return reference.Value; + } +} + +#endif diff --git a/src/Arch/Core/Utils/Ref.cs b/src/Arch/Core/Utils/Ref.cs new file mode 100644 index 00000000..02be4816 --- /dev/null +++ b/src/Arch/Core/Utils/Ref.cs @@ -0,0 +1,56 @@ +namespace Arch.Core.Utils; + +#if NETSTANDARD2_1_OR_GREATER || NET6_0 + +/// +/// The strct +/// can store a reference to a value of a specified type. +/// +/// The type of value to reference. +public readonly ref struct Ref +{ + /// + /// The 1-length instance used to track the target value. + /// + internal readonly Span Span; + + /// + /// Initializes a new instance of the struct. + /// + /// The reference to the target value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Ref(ref T value) + { + this.Span = MemoryMarshal.CreateSpan(ref value, 1); + } + + /// + /// Initializes a new instance of the struct. + /// + /// The pointer to the target value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe Ref(void* pointer) + : this(ref Unsafe.AsRef(pointer)) + { + } + + /// + /// Gets the reference represented by the current instance. + /// + public ref T Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref MemoryMarshal.GetReference(this.Span); + } + + /// + /// Implicitly gets the value from a given instance. + /// + /// The input instance. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator T(Ref reference) + { + return reference.Value; + } +} +#endif