Mark version increments with directives and update generator

This commit is contained in:
Marek Lemańczyk committed 2025-07-14 21:28:52 +02:00
1 parent 1abc07e9a2
commit 29a5db476e
7 files changed
+262 -10

No files matched your search

@@ -2,7 +2,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks> <TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<DefineConstants>$(DefineConstants);WITH_VERSIONING</DefineConstants>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Recyclable.Collections</PackageId> <PackageId>Recyclable.Collections</PackageId>
<PackageVersion>0.0.6</PackageVersion> <PackageVersion>0.0.6</PackageVersion>
@@ -30,8 +31,12 @@
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.5" /> <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.5" />
<PackageReference Include="morelinq" Version="3.4.2" /> <PackageReference Include="morelinq" Version="3.4.2" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VersionedCollectionsGenerator\VersionedCollectionsGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project> </Project>
@@ -126,8 +126,9 @@ namespace Recyclable.Collections
list._count = currentItemsCount; list._count = currentItemsCount;
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static void AddRange<T>(this RecyclableList<T> list, in Array items) [VersionedCollectionsGenerator.RewriteForVersioned]
public static void AddRange<T>(this RecyclableList<T> list, in Array items)
{ {
if (list._capacity < list._count + items.Length) if (list._capacity < list._count + items.Length)
{ {
@@ -136,7 +137,9 @@ namespace Recyclable.Collections
Array.Copy(items, items.GetLowerBound(0), list._memoryBlock, list._count, items.Length); Array.Copy(items, items.GetLowerBound(0), list._memoryBlock, list._count, items.Length);
list._count += items.Length; list._count += items.Length;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -149,7 +152,9 @@ namespace Recyclable.Collections
new ReadOnlySpan<T>(items).CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length)); new ReadOnlySpan<T>(items).CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length));
list._count += items.Length; list._count += items.Length;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -162,7 +167,9 @@ namespace Recyclable.Collections
items.CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length)); items.CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length));
list._count += items.Length; list._count += items.Length;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -175,7 +182,9 @@ namespace Recyclable.Collections
items.CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length)); items.CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length));
list._count += items.Length; list._count += items.Length;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -188,7 +197,9 @@ namespace Recyclable.Collections
items.CopyTo(list._memoryBlock, list._count); items.CopyTo(list._memoryBlock, list._count);
list._count += items.Count; list._count += items.Count;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -201,7 +212,9 @@ namespace Recyclable.Collections
items.CopyTo(list._memoryBlock, list._count); items.CopyTo(list._memoryBlock, list._count);
list._count += items.Count; list._count += items.Count;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -214,7 +227,9 @@ namespace Recyclable.Collections
items.CopyTo(list._memoryBlock, list._count); items.CopyTo(list._memoryBlock, list._count);
list._count += items.Count; list._count += items.Count;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -227,7 +242,9 @@ namespace Recyclable.Collections
new ReadOnlySpan<T>(items._memoryBlock, 0, items._count).CopyTo(new Span<T>(list._memoryBlock, list._count, items._count)); new ReadOnlySpan<T>(items._memoryBlock, 0, items._count).CopyTo(new Span<T>(list._memoryBlock, list._count, items._count));
list._count += items._count; list._count += items._count;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -278,7 +295,9 @@ namespace Recyclable.Collections
} }
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -309,7 +328,9 @@ namespace Recyclable.Collections
} }
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -349,7 +370,9 @@ namespace Recyclable.Collections
} }
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -372,7 +395,9 @@ namespace Recyclable.Collections
new ReadOnlySpan<T>(items._items, 0, sourceCount).CopyTo(new Span<T>(list._memoryBlock, oldCount, sourceCount)); new ReadOnlySpan<T>(items._items, 0, sourceCount).CopyTo(new Span<T>(list._memoryBlock, oldCount, sourceCount));
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -411,7 +436,9 @@ namespace Recyclable.Collections
} }
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -434,7 +461,9 @@ namespace Recyclable.Collections
new ReadOnlySpan<T>(items._heap, 0, sourceCount).CopyTo(new Span<T>(list._memoryBlock, oldCount, sourceCount)); new ReadOnlySpan<T>(items._heap, 0, sourceCount).CopyTo(new Span<T>(list._memoryBlock, oldCount, sourceCount));
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -473,7 +502,9 @@ namespace Recyclable.Collections
} }
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -505,7 +536,9 @@ namespace Recyclable.Collections
} }
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -532,7 +565,9 @@ namespace Recyclable.Collections
} }
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
public static IEnumerator AddRange<T>(this RecyclableList<T> list, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength) public static IEnumerator AddRange<T>(this RecyclableList<T> list, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength)
@@ -656,12 +691,16 @@ namespace Recyclable.Collections
else if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity) && requiredAdditionalCapacity != 0) else if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity) && requiredAdditionalCapacity != 0)
{ {
AddRangeWithKnownCount(list, items, list._count, requiredAdditionalCapacity); AddRangeWithKnownCount(list, items, list._count, requiredAdditionalCapacity);
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
else else
{ {
AddRangeEnumerated(list, items, growByCount); AddRangeEnumerated(list, items, growByCount);
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
} }
} }
@@ -79,7 +79,9 @@ namespace Recyclable.Collections
} }
list._count += requiredAdditionalCapacity; list._count += requiredAdditionalCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -94,7 +96,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
Array.Copy(items, items.GetLowerBound(0), memoryBlock, index, items.Length); Array.Copy(items, items.GetLowerBound(0), memoryBlock, index, items.Length);
list._count += items.Length; list._count += items.Length;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -109,7 +113,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
new ReadOnlySpan<T>(items).CopyTo(new Span<T>(memoryBlock, index, items.Length)); new ReadOnlySpan<T>(items).CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length; list._count += items.Length;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -124,7 +130,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
items.CopyTo(new Span<T>(memoryBlock, index, items.Length)); items.CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length; list._count += items.Length;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -139,7 +147,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Length, list._count - index);
items.CopyTo(new Span<T>(memoryBlock, index, items.Length)); items.CopyTo(new Span<T>(memoryBlock, index, items.Length));
list._count += items.Length; list._count += items.Length;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -154,7 +164,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(memoryBlock, index); items.CopyTo(memoryBlock, index);
list._count += items.Count; list._count += items.Count;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -169,7 +181,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(list._memoryBlock, index); items.CopyTo(list._memoryBlock, index);
list._count += items.Count; list._count += items.Count;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -184,7 +198,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
items.CopyTo(memoryBlock, index); items.CopyTo(memoryBlock, index);
list._count += items.Count; list._count += items.Count;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -199,7 +215,9 @@ namespace Recyclable.Collections
Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index); Array.Copy(memoryBlock, index, memoryBlock, index + items.Count, list._count - index);
new ReadOnlySpan<T>(items._memoryBlock, 0, items._count).CopyTo(new(list._memoryBlock, index, items._count)); new ReadOnlySpan<T>(items._memoryBlock, 0, items._count).CopyTo(new(list._memoryBlock, index, items._count));
list._count += items._count; list._count += items._count;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
@@ -251,7 +269,9 @@ namespace Recyclable.Collections
} }
list._count = targetCapacity; list._count = targetCapacity;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
public static IEnumerator InsertRange<T>(this RecyclableList<T> list, int index, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength) public static IEnumerator InsertRange<T>(this RecyclableList<T> list, int index, IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength)
@@ -101,7 +101,9 @@ namespace Recyclable.Collections
} }
list._count -= foundItemsCount; list._count -= foundItemsCount;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
return foundItemsCount; return foundItemsCount;
} }
@@ -125,43 +127,57 @@ namespace Recyclable.Collections
} }
list._count -= count; list._count -= count;
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
public static void Reverse<T>(this RecyclableList<T> list) public static void Reverse<T>(this RecyclableList<T> list)
{ {
Array.Reverse(list._memoryBlock, 0, list._count); Array.Reverse(list._memoryBlock, 0, list._count);
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
public static void Reverse<T>(this RecyclableList<T> list, int index, int count) public static void Reverse<T>(this RecyclableList<T> list, int index, int count)
{ {
Array.Reverse(list._memoryBlock, index, count); Array.Reverse(list._memoryBlock, index, count);
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
public static void Sort<T>(this RecyclableList<T> list) public static void Sort<T>(this RecyclableList<T> list)
{ {
Array.Sort(list._memoryBlock, 0, list._count); Array.Sort(list._memoryBlock, 0, list._count);
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
public static void Sort<T>(this RecyclableList<T> list, Comparison<T> comparison) public static void Sort<T>(this RecyclableList<T> list, Comparison<T> comparison)
{ {
Array.Sort(list._memoryBlock, 0, list._count, new ComparisonToComparerAdapter<T>(comparison)); Array.Sort(list._memoryBlock, 0, list._count, new ComparisonToComparerAdapter<T>(comparison));
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
public static void Sort<T>(this RecyclableList<T> list, IComparer<T>? comparer) public static void Sort<T>(this RecyclableList<T> list, IComparer<T>? comparer)
{ {
Array.Sort(list._memoryBlock, 0, list._count, comparer); Array.Sort(list._memoryBlock, 0, list._count, comparer);
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
public static void Sort<T>(this RecyclableList<T> list, int index, int count, IComparer<T>? comparer) public static void Sort<T>(this RecyclableList<T> list, int index, int count, IComparer<T>? comparer)
{ {
Array.Sort(list._memoryBlock, index, count, comparer); Array.Sort(list._memoryBlock, index, count, comparer);
#if WITH_VERSIONING
list._version++; list._version++;
#endif
} }
public static T[] ToArray<T>(this RecyclableList<T> list) public static T[] ToArray<T>(this RecyclableList<T> list)
+23 -3
View File
@@ -5,8 +5,9 @@ using Recyclable.Collections.Pools;
namespace Recyclable.Collections namespace Recyclable.Collections
{ {
[Serializable] [Serializable]
public sealed partial class RecyclableList<T> : IList<T>, IReadOnlyList<T>, IDisposable [VersionedCollectionsGenerator.GenerateVersioned]
public sealed partial class RecyclableList<T> : IList<T>, IReadOnlyList<T>, IDisposable
{ {
internal static readonly bool _needsClearing = !typeof(T).IsValueType; internal static readonly bool _needsClearing = !typeof(T).IsValueType;
@@ -17,7 +18,8 @@ namespace Recyclable.Collections
#nullable restore #nullable restore
internal ulong _version; internal ulong _version;
public ulong Version => _version; [VersionedCollectionsGenerator.CloneForVersioned]
public ulong Version => _version;
public RecyclableList() public RecyclableList()
{ {
@@ -172,7 +174,9 @@ namespace Recyclable.Collections
set set
{ {
_memoryBlock[index] = value; _memoryBlock[index] = value;
#if WITH_VERSIONING
_version++; _version++;
#endif
} }
} }
@@ -185,7 +189,9 @@ namespace Recyclable.Collections
if (_capacity != value) if (_capacity != value)
{ {
_capacity = RecyclableListHelpers<T>.EnsureCapacity(this, _count, checked((int)BitOperations.RoundUpToPowerOf2((uint)value))); _capacity = RecyclableListHelpers<T>.EnsureCapacity(this, _count, checked((int)BitOperations.RoundUpToPowerOf2((uint)value)));
#if WITH_VERSIONING
_version++; _version++;
#endif
} }
} }
} }
@@ -204,7 +210,9 @@ namespace Recyclable.Collections
} }
_count = value; _count = value;
#if WITH_VERSIONING
_version++; _version++;
#endif
} }
} }
} }
@@ -243,7 +251,9 @@ namespace Recyclable.Collections
} }
_memoryBlock[_count++] = item; _memoryBlock[_count++] = item;
#if WITH_VERSIONING
_version++; _version++;
#endif
} }
public T[] AsArray => _memoryBlock; public T[] AsArray => _memoryBlock;
@@ -262,7 +272,9 @@ namespace Recyclable.Collections
} }
_count = 0; _count = 0;
#if WITH_VERSIONING
_version++; _version++;
#endif
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -295,7 +307,9 @@ namespace Recyclable.Collections
_memoryBlock[index] = item; _memoryBlock[index] = item;
_count++; _count++;
#if WITH_VERSIONING
_version++; _version++;
#endif
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
@@ -315,7 +329,9 @@ namespace Recyclable.Collections
_memoryBlock[_count] = default; _memoryBlock[_count] = default;
} }
#if WITH_VERSIONING
_version++; _version++;
#endif
return true; return true;
} }
@@ -342,7 +358,9 @@ namespace Recyclable.Collections
_memoryBlock[_count] = default; _memoryBlock[_count] = default;
} }
#if WITH_VERSIONING
_version++; _version++;
#endif
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -356,7 +374,9 @@ namespace Recyclable.Collections
public void Dispose() public void Dispose()
{ {
#if WITH_VERSIONING
_version++; _version++;
#endif
if (_count != 0) if (_count != 0)
{ {
if (_needsClearing) if (_needsClearing)
@@ -0,0 +1,133 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace VersionedCollectionsGenerator
{
[Generator]
public sealed class VersionedCollectionsGenerator : ISourceGenerator
{
private const string AttributeText = """
using System;
namespace VersionedCollectionsGenerator
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
internal sealed class GenerateVersionedAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
internal sealed class CloneForVersionedAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
internal sealed class RewriteForVersionedAttribute : Attribute
{
}
}
""";
public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
context.AddSource("GenerateVersionedAttribute.g.cs", SourceText.From(AttributeText, Encoding.UTF8));
if (context.SyntaxReceiver is not SyntaxReceiver receiver)
{
return;
}
foreach (var candidate in receiver.Candidates)
{
var model = context.Compilation.GetSemanticModel(candidate.SyntaxTree);
var symbol = model.GetDeclaredSymbol(candidate) as INamedTypeSymbol;
if (symbol is null)
{
continue;
}
if (!symbol.GetAttributes().Any(a => a.AttributeClass?.ToDisplayString() == "VersionedCollectionsGenerator.GenerateVersionedAttribute"))
{
continue;
}
string originalName = symbol.Name;
string newName = $"{originalName}Versioned";
var partials = GetAllPartials(context.Compilation, originalName);
int index = 0;
foreach (var partial in partials)
{
var tree = partial.SyntaxTree;
var root = tree.GetRoot();
var rewriter = new RenameRewriter(originalName, newName);
var newRoot = rewriter.Visit(root);
var text = newRoot.ToFullString()
.Replace("#if WITH_VERSIONING", string.Empty)
.Replace("#endif", string.Empty);
context.AddSource($"{newName}_{index++}.g.cs", SourceText.From(text, Encoding.UTF8));
}
}
}
private static IEnumerable<ClassDeclarationSyntax> GetAllPartials(Compilation compilation, string className)
{
foreach (var tree in compilation.SyntaxTrees)
{
var root = tree.GetRoot();
foreach (var cls in root.DescendantNodes().OfType<ClassDeclarationSyntax>())
{
if (cls.Identifier.ValueText == className)
{
yield return cls;
}
}
}
}
private sealed class RenameRewriter : CSharpSyntaxRewriter
{
private readonly string _oldName;
private readonly string _newName;
public RenameRewriter(string oldName, string newName)
{
_oldName = oldName;
_newName = newName;
}
public override SyntaxToken VisitToken(SyntaxToken token)
{
if (token.ValueText == _oldName)
{
return SyntaxFactory.Identifier(token.LeadingTrivia, _newName, token.TrailingTrivia);
}
return base.VisitToken(token);
}
}
private sealed class SyntaxReceiver : ISyntaxReceiver
{
public List<ClassDeclarationSyntax> Candidates { get; } = new();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is ClassDeclarationSyntax classDecl && classDecl.AttributeLists.Count > 0)
{
Candidates.Add(classDecl);
}
}
}
}
}
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
<EnforceExtendedAnalyzerRules>True</EnforceExtendedAnalyzerRules>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
</ItemGroup>
</Project>