Skip to content

Commit

Permalink
Updated to CommunityToolkit 8.2.2 and added Ref and ReadOnlyRef for .…
Browse files Browse the repository at this point in the history
…NetStandard2.1
  • Loading branch information
genaray committed Apr 17, 2024
1 parent b434352 commit f26c729
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/Arch.SourceGen/QueryGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 2 additions & 3 deletions src/Arch/Arch.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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. </PackageReleaseNotes>
CommandBuffer now accepts a world during playback, world in ctor was removed.</PackageReleaseNotes>
<PackageTags>c#;.net;.net6;.net7;ecs;game;entity;gamedev; game-development; game-engine; entity-component-system;stride;unity;godot;</PackageTags>

<PackageProjectUrl>https://github.com/genaray/Arch</PackageProjectUrl>
Expand Down Expand Up @@ -103,7 +102,7 @@ CommandBuffer now triggers OnComponentRemoved events. </PackageReleaseNotes>
<ItemGroup>
<PackageReference Include="Arch.LowLevel" Version="1.1.0" />
<PackageReference Include="Collections.Pooled" Version="2.0.0-preview.27" />
<PackageReference Include="CommunityToolkit.HighPerformance" Version="7.1.2" />
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.2.2" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="ZeroAllocJobScheduler" Version="1.1.2" />
Expand Down
3 changes: 1 addition & 2 deletions src/Arch/Core/Chunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public T[] GetArray<T>()
{
var index = Index<T>();
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<T[]>(array);
}

Expand Down Expand Up @@ -288,7 +288,6 @@ public Span<T> GetSpan<T>()

public partial struct Chunk
{

/// <summary>
/// Sets or replaces a component for an index in the chunk.
/// This won't fire an event for <see cref="ComponentSetHandler{T}"/>.
Expand Down
1 change: 1 addition & 0 deletions src/Arch/Core/Enumerators.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Arch.Core.Extensions.Internal;
using Arch.Core.Utils;
using CommunityToolkit.HighPerformance;

namespace Arch.Core;
Expand Down
71 changes: 71 additions & 0 deletions src/Arch/Core/Utils/ReadOnlyRef.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using CommunityToolkit.HighPerformance.Helpers;

namespace Arch.Core.Utils;

#if NETSTANDARD2_1_OR_GREATER || NET6_0

/// <summary>
/// The <see langword="struct"/> struct
/// can store a readonly reference to a value of a specified type.
/// </summary>
/// <typeparam name="T">The type of value to reference.</typeparam>
public readonly ref struct ReadOnlyRef<T>
{
/// <summary>
/// The 1-length <see cref="ReadOnlySpan{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
internal readonly ReadOnlySpan<T> Span;

/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="value">The readonly reference to the target <typeparamref name="T"/> value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlyRef(in T value)
{
ref T r0 = ref Unsafe.AsRef(value);

this.Span = MemoryMarshal.CreateReadOnlySpan(ref r0, 1);
}

/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="pointer">The pointer to the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe ReadOnlyRef(void* pointer)
: this(in Unsafe.AsRef<T>(pointer))
{
}

/// <summary>
/// Gets the readonly <typeparamref name="T"/> reference represented by the current <see cref="Ref{T}"/> instance.
/// </summary>
public ref readonly T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref MemoryMarshal.GetReference(this.Span);
}

/// <summary>
/// Implicitly converts a <see cref="Ref{T}"/> instance into a <see cref="ReadOnlyRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlyRef<T>(Ref<T> reference)
{
return new(in reference.Value);
}

/// <summary>
/// Implicitly gets the <typeparamref name="T"/> value from a given <see cref="ReadOnlyRef{T}"/> instance.
/// </summary>
/// <param name="reference">The input <see cref="ReadOnlyRef{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator T(ReadOnlyRef<T> reference)
{
return reference.Value;
}
}

#endif
56 changes: 56 additions & 0 deletions src/Arch/Core/Utils/Ref.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
namespace Arch.Core.Utils;

#if NETSTANDARD2_1_OR_GREATER || NET6_0

/// <summary>
/// The <see langword="struct"/> strct
/// can store a reference to a value of a specified type.
/// </summary>
/// <typeparam name="T">The type of value to reference.</typeparam>
public readonly ref struct Ref<T>
{
/// <summary>
/// The 1-length <see cref="Span{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
internal readonly Span<T> Span;

/// <summary>
/// Initializes a new instance of the <see cref="Ref{T}"/> struct.
/// </summary>
/// <param name="value">The reference to the target <typeparamref name="T"/> value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Ref(ref T value)
{
this.Span = MemoryMarshal.CreateSpan(ref value, 1);
}

/// <summary>
/// Initializes a new instance of the <see cref="Ref{T}"/> struct.
/// </summary>
/// <param name="pointer">The pointer to the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe Ref(void* pointer)
: this(ref Unsafe.AsRef<T>(pointer))
{
}

/// <summary>
/// Gets the <typeparamref name="T"/> reference represented by the current <see cref="Ref{T}"/> instance.
/// </summary>
public ref T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref MemoryMarshal.GetReference(this.Span);
}

/// <summary>
/// Implicitly gets the <typeparamref name="T"/> value from a given <see cref="Ref{T}"/> instance.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator T(Ref<T> reference)
{
return reference.Value;
}
}
#endif

0 comments on commit f26c729

Please sign in to comment.