diff --git a/README.md b/README.md
index 5fcdcb3..d8cefac 100644
--- a/README.md
+++ b/README.md
@@ -56,5 +56,6 @@ It also includes the following optional runtime-supported polyfills:
**PolySharp**'s generation can be configured through some MSBuild properties to set in consuming projects.
The following properties are available:
-- "PolySharpUsePublicAccessibilityForGeneratedTypes": changes the accessibility of generated types from `internal` to `public`.
-- "PolySharpIncludeRuntimeSupportedAttributes": enables polyfills for (dummy) runtime-supported attributes too.
\ No newline at end of file
+- "PolySharpUsePublicAccessibilityForGeneratedTypes": makes all generated types public.
+- "PolySharpIncludeRuntimeSupportedAttributes": enables polyfills for (dummy) runtime-supported attributes too.
+- "PolySharpExcludeGeneratedTypes": excludes specific types from generation (';' or ',' separated type names).
\ No newline at end of file
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.StackTraceHiddenAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.StackTraceHiddenAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Diagnostics.StackTraceHiddenAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Diagnostics.StackTraceHiddenAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.ObsoletedOSPlatformAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.ObsoletedOSPlatformAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.ObsoletedOSPlatformAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.ObsoletedOSPlatformAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.SupportedOSPlatformAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.SupportedOSPlatformAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.SupportedOSPlatformAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.SupportedOSPlatformAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.SupportedOSPlatformGuardAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.SupportedOSPlatformGuardAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.SupportedOSPlatformGuardAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.SupportedOSPlatformGuardAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.TargetPlatformAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.TargetPlatformAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.TargetPlatformAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.TargetPlatformAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.UnsupportedOSPlatformAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.UnsupportedOSPlatformAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.UnsupportedOSPlatformAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.UnsupportedOSPlatformAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.UnsupportedOSPlatformGuardAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.UnsupportedOSPlatformGuardAttribute.cs
similarity index 100%
rename from src/PolySharp.SourceGenerators/EmbeddedResources/Compatibility/System.Runtime.Versioning.UnsupportedOSPlatformGuardAttribute.cs
rename to src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.Versioning.UnsupportedOSPlatformGuardAttribute.cs
diff --git a/src/PolySharp.SourceGenerators/Extensions/AnalyzerConfigOptionsProviderExtensions.cs b/src/PolySharp.SourceGenerators/Extensions/AnalyzerConfigOptionsProviderExtensions.cs
index d4b0af9..ff5227f 100644
--- a/src/PolySharp.SourceGenerators/Extensions/AnalyzerConfigOptionsProviderExtensions.cs
+++ b/src/PolySharp.SourceGenerators/Extensions/AnalyzerConfigOptionsProviderExtensions.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Immutable;
+using ComputeSharp.SourceGeneration.Helpers;
using Microsoft.CodeAnalysis.Diagnostics;
namespace PolySharp.SourceGenerators.Extensions;
@@ -26,4 +28,32 @@ public static bool GetBoolMSBuildProperty(this AnalyzerConfigOptionsProvider opt
options.GlobalOptions.TryGetValue($"build_property.{propertyName}", out string? propertyValue) &&
string.Equals(propertyValue, bool.TrueString, StringComparison.OrdinalIgnoreCase);
}
+
+ ///
+ /// Gets the value of an MSBuild property representing a semicolon-separated list of -s.
+ ///
+ /// The input instance.
+ /// The MSBuild property name.
+ /// The value of the specified MSBuild property.
+ public static ImmutableArray GetStringArrayMSBuildProperty(this AnalyzerConfigOptionsProvider options, string propertyName)
+ {
+ if (options.GlobalOptions.TryGetValue($"build_property.{propertyName}", out string? propertyValue))
+ {
+ using ImmutableArrayBuilder builder = ImmutableArrayBuilder.Rent();
+
+ foreach (string part in propertyValue.Split(',', ';'))
+ {
+ string trimmed = part.Trim();
+
+ if (trimmed.Length > 0)
+ {
+ builder.Add(trimmed);
+ }
+ }
+
+ return builder.ToImmutable();
+ }
+
+ return ImmutableArray.Empty;
+ }
}
\ No newline at end of file
diff --git a/src/PolySharp.SourceGenerators/Extensions/IncrementalValueProviderExtensions.cs b/src/PolySharp.SourceGenerators/Extensions/IncrementalValueProviderExtensions.cs
deleted file mode 100644
index 31af032..0000000
--- a/src/PolySharp.SourceGenerators/Extensions/IncrementalValueProviderExtensions.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.CodeAnalysis;
-
-namespace PolySharp.SourceGenerators.Extensions;
-
-///
-/// Extension methods for the type.
-///
-internal static class IncrementalValueProviderExtensions
-{
- ///
- /// Combines three instances.
- ///
- /// The type of values produced by the first input.
- /// The type of values produced by the second input.
- /// The type of values produced by the third input.
- /// The first input.
- /// The second input.
- /// The third input.
- /// The resulting combined result.
- public static IncrementalValueProvider<(T1, T2, T3)> Combine(
- this IncrementalValueProvider source1,
- IncrementalValueProvider source2,
- IncrementalValueProvider source3)
- {
- return
- source1
- .Combine(source2)
- .Combine(source3)
- .Select(static (items, _) => (items.Left.Left, items.Left.Right, items.Right));
- }
-}
\ No newline at end of file
diff --git a/src/PolySharp.SourceGenerators/Helpers/EquatableArray{T}.cs b/src/PolySharp.SourceGenerators/Helpers/EquatableArray{T}.cs
new file mode 100644
index 0000000..74b57dc
--- /dev/null
+++ b/src/PolySharp.SourceGenerators/Helpers/EquatableArray{T}.cs
@@ -0,0 +1,219 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace PolySharp.SourceGenerators.Helpers;
+
+///
+/// Extensions for .
+///
+internal static class EquatableArray
+{
+ ///
+ /// Creates an instance from a given .
+ ///
+ /// The type of items in the input array.
+ /// The input instance.
+ /// An instance from a given .
+ public static EquatableArray AsEquatableArray(this ImmutableArray array)
+ where T : IEquatable
+ {
+ return new(array);
+ }
+}
+
+///
+/// An imutable, equatable array. This is equivalent to but with value equality support.
+///
+/// The type of values in the array.
+internal readonly struct EquatableArray : IEquatable>, IEnumerable
+ where T : IEquatable
+{
+ ///
+ /// The underlying array.
+ ///
+ private readonly T[]? array;
+
+ ///
+ /// Creates a new instance.
+ ///
+ /// The input to wrap.
+ public EquatableArray(ImmutableArray array)
+ {
+ this.array = Unsafe.As, T[]?>(ref array);
+ }
+
+ ///
+ /// Gets a reference to an item at a specified position within the array.
+ ///
+ /// The index of the item to retrieve a reference to.
+ /// A reference to an item at a specified position within the array.
+ public T this[int index]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => AsImmutableArray()[index];
+ }
+
+ ///
+ /// Gets a value indicating whether the current array is empty.
+ ///
+ public bool IsEmpty
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => AsImmutableArray().IsEmpty;
+ }
+
+ ///
+ /// Gets a value indicating whether the current array is default or empty.
+ ///
+ public bool IsDefaultOrEmpty
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => AsImmutableArray().IsDefaultOrEmpty;
+ }
+
+ ///
+ /// Gets the length of the current array.
+ ///
+ public int Length
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => AsImmutableArray().Length;
+ }
+
+ ///
+ public bool Equals(EquatableArray array)
+ {
+ return AsSpan().SequenceEqual(array.AsSpan());
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ {
+ return obj is EquatableArray array && Equals(this, array);
+ }
+
+ ///
+ public override unsafe int GetHashCode()
+ {
+ if (this.array is not T[] array)
+ {
+ return 0;
+ }
+
+ int hashCode = 0;
+
+ foreach (T value in array)
+ {
+ hashCode = unchecked((hashCode * (int)0xA5555529) + value.GetHashCode());
+ }
+
+ return hashCode;
+ }
+
+ ///
+ /// Gets an instance from the current .
+ ///
+ /// The from the current .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ImmutableArray AsImmutableArray()
+ {
+ return Unsafe.As>(ref Unsafe.AsRef(in this.array));
+ }
+
+ ///
+ /// Creates an instance from a given .
+ ///
+ /// The input instance.
+ /// An instance from a given .
+ public static EquatableArray FromImmutableArray(ImmutableArray array)
+ {
+ return new(array);
+ }
+
+ ///
+ /// Returns a wrapping the current items.
+ ///
+ /// A wrapping the current items.
+ public ReadOnlySpan AsSpan()
+ {
+ return AsImmutableArray().AsSpan();
+ }
+
+ ///
+ /// Copies the contents of this instance. to a mutable array.
+ ///
+ /// The newly instantiated array.
+ public T[] ToArray()
+ {
+ return AsImmutableArray().ToArray();
+ }
+
+ ///
+ /// Gets an value to traverse items in the current array.
+ ///
+ /// An value to traverse items in the current array.
+ public ImmutableArray.Enumerator GetEnumerator()
+ {
+ return AsImmutableArray().GetEnumerator();
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable)AsImmutableArray()).GetEnumerator();
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable)AsImmutableArray()).GetEnumerator();
+ }
+
+ ///
+ /// Implicitly converts an to .
+ ///
+ /// An instance from a given .
+ public static implicit operator EquatableArray(ImmutableArray array)
+ {
+ return FromImmutableArray(array);
+ }
+
+ ///
+ /// Implicitly converts an to .
+ ///
+ /// An instance from a given .
+ public static implicit operator ImmutableArray(EquatableArray array)
+ {
+ return array.AsImmutableArray();
+ }
+
+ ///
+ /// Checks whether two values are the same.
+ ///
+ /// The first value.
+ /// The second value.
+ /// Whether and are equal.
+ public static bool operator ==(EquatableArray left, EquatableArray right)
+ {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Checks whether two values are not the same.
+ ///
+ /// The first value.
+ /// The second value.
+ /// Whether and are not equal.
+ public static bool operator !=(EquatableArray left, EquatableArray right)
+ {
+ return !left.Equals(right);
+ }
+}
\ No newline at end of file
diff --git a/src/PolySharp.SourceGenerators/Helpers/ImmutableArrayBuilder{T}.cs b/src/PolySharp.SourceGenerators/Helpers/ImmutableArrayBuilder{T}.cs
new file mode 100644
index 0000000..1cce225
--- /dev/null
+++ b/src/PolySharp.SourceGenerators/Helpers/ImmutableArrayBuilder{T}.cs
@@ -0,0 +1,234 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Immutable;
+using System.Runtime.CompilerServices;
+
+namespace ComputeSharp.SourceGeneration.Helpers;
+
+///
+/// A helper type to build sequences of values with pooled buffers.
+///
+/// The type of items to create sequences for.
+internal struct ImmutableArrayBuilder : IDisposable
+{
+ ///
+ /// The shared instance to share objects.
+ ///
+ private static readonly ObjectPool SharedObjectPool = new(static () => new Writer());
+
+ ///
+ /// The owner instance.
+ ///
+ private readonly ObjectPool objectPool;
+
+ ///
+ /// The rented instance to use.
+ ///
+ private Writer? writer;
+
+ ///
+ /// Creates a value with a pooled underlying data writer.
+ ///
+ /// A instance to write data to.
+ public static ImmutableArrayBuilder Rent()
+ {
+ return new(SharedObjectPool, SharedObjectPool.Allocate());
+ }
+
+ ///
+ /// Creates a new object with the specified parameters.
+ ///
+ /// The target to return to.
+ /// The target data writer to use.
+ private ImmutableArrayBuilder(ObjectPool objectPool, Writer writer)
+ {
+ this.objectPool = objectPool;
+ this.writer = writer;
+ }
+
+ ///
+ /// Gets the data written to the underlying buffer so far, as a .
+ ///
+ public readonly ReadOnlySpan WrittenSpan
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => this.writer!.WrittenSpan;
+ }
+
+ ///
+ /// Gets the number of elements currently written in the current instance.
+ ///
+ public readonly int Count
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => this.writer!.WrittenSpan.Length;
+ }
+
+ ///
+ public readonly void Add(T item)
+ {
+ this.writer!.Add(item);
+ }
+
+ ///
+ /// Adds the specified items to the end of the array.
+ ///
+ /// The items to add at the end of the array.
+ public readonly void AddRange(ReadOnlySpan items)
+ {
+ this.writer!.AddRange(items);
+ }
+
+ ///
+ public readonly ImmutableArray ToImmutable()
+ {
+ T[] array = this.writer!.WrittenSpan.ToArray();
+
+ return Unsafe.As>(ref array);
+ }
+
+ ///
+ public readonly T[] ToArray()
+ {
+ return this.writer!.WrittenSpan.ToArray();
+ }
+
+ ///
+ public override readonly string ToString()
+ {
+ return this.writer!.WrittenSpan.ToString();
+ }
+
+ ///
+ public void Dispose()
+ {
+ Writer? writer = this.writer;
+
+ this.writer = null;
+
+ if (writer is not null)
+ {
+ writer.Clear();
+
+ this.objectPool.Free(writer);
+ }
+ }
+
+ ///
+ /// A class handling the actual buffer writing.
+ ///
+ private sealed class Writer
+ {
+ ///
+ /// The underlying array.
+ ///
+ private T[] array;
+
+ ///
+ /// The starting offset within .
+ ///
+ private int index;
+
+ ///
+ /// Creates a new instance with the specified parameters.
+ ///
+ public Writer()
+ {
+ if (typeof(T) == typeof(char))
+ {
+ this.array = new T[1024];
+ }
+ else
+ {
+ this.array = new T[8];
+ }
+
+ this.index = 0;
+ }
+
+ ///
+ public ReadOnlySpan WrittenSpan
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => new(this.array, 0, this.index);
+ }
+
+ ///
+ public void Add(T value)
+ {
+ EnsureCapacity(1);
+
+ this.array[this.index++] = value;
+ }
+
+ ///
+ public void AddRange(ReadOnlySpan items)
+ {
+ EnsureCapacity(items.Length);
+
+ items.CopyTo(this.array.AsSpan(this.index));
+
+ this.index += items.Length;
+ }
+
+ ///
+ /// Clears the items in the current writer.
+ ///
+ public void Clear()
+ {
+ if (typeof(T) != typeof(char))
+ {
+ this.array.AsSpan(0, this.index).Clear();
+ }
+
+ this.index = 0;
+ }
+
+ ///
+ /// Ensures that has enough free space to contain a given number of new items.
+ ///
+ /// The minimum number of items to ensure space for in .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void EnsureCapacity(int requestedSize)
+ {
+ if (requestedSize > this.array.Length - this.index)
+ {
+ ResizeBuffer(requestedSize);
+ }
+ }
+
+ ///
+ /// Resizes to ensure it can fit the specified number of new items.
+ ///
+ /// The minimum number of items to ensure space for in .
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void ResizeBuffer(int sizeHint)
+ {
+ int minimumSize = this.index + sizeHint;
+ int requestedSize = Math.Max(this.array.Length * 2, minimumSize);
+
+ T[] newArray = new T[requestedSize];
+
+ Array.Copy(this.array, newArray, this.index);
+
+ this.array = newArray;
+ }
+ }
+}
+
+///
+/// Private helpers for the type.
+///
+file static class ImmutableArrayBuilder
+{
+ ///
+ /// Throws an for "index".
+ ///
+ public static void ThrowArgumentOutOfRangeExceptionForIndex()
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+}
\ No newline at end of file
diff --git a/src/PolySharp.SourceGenerators/Helpers/ObjectPool{T}.cs b/src/PolySharp.SourceGenerators/Helpers/ObjectPool{T}.cs
new file mode 100644
index 0000000..b025cf9
--- /dev/null
+++ b/src/PolySharp.SourceGenerators/Helpers/ObjectPool{T}.cs
@@ -0,0 +1,163 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Ported from Roslyn, see: https://github.com/dotnet/roslyn/blob/main/src/Dependencies/PooledObjects/ObjectPool%601.cs.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace ComputeSharp.SourceGeneration.Helpers;
+
+///
+///
+/// Generic implementation of object pooling pattern with predefined pool size limit. The main purpose
+/// is that limited number of frequently used objects can be kept in the pool for further recycling.
+///
+///
+/// Notes:
+///
+/// -
+/// It is not the goal to keep all returned objects. Pool is not meant for storage. If there
+/// is no space in the pool, extra returned objects will be dropped.
+///
+/// -
+/// It is implied that if object was obtained from a pool, the caller will return it back in
+/// a relatively short time. Keeping checked out objects for long durations is ok, but
+/// reduces usefulness of pooling. Just new up your own.
+///
+///
+///
+///
+/// Not returning objects to the pool in not detrimental to the pool's work, but is a bad practice.
+/// Rationale: if there is no intent for reusing the object, do not use pool - just use "new".
+///
+///
+/// The type of objects to pool.
+internal sealed class ObjectPool
+ where T : class
+{
+ ///
+ /// The factory is stored for the lifetime of the pool. We will call this only when pool needs to
+ /// expand. compared to "new T()", Func gives more flexibility to implementers and faster than "new T()".
+ ///
+ private readonly Func factory;
+
+ ///
+ /// The array of cached items.
+ ///
+ private readonly Element[] items;
+
+ ///
+ /// Storage for the pool objects. The first item is stored in a dedicated field
+ /// because we expect to be able to satisfy most requests from it.
+ ///
+ private T? firstItem;
+
+ ///
+ /// Creates a new instance with the specified parameters.
+ ///
+ /// The input factory to produce items.
+ public ObjectPool(Func factory)
+ : this(factory, Environment.ProcessorCount * 2)
+ {
+ }
+
+ ///
+ /// Creates a new instance with the specified parameters.
+ ///
+ /// The input factory to produce items.
+ /// The pool size to use.
+ public ObjectPool(Func factory, int size)
+ {
+ this.factory = factory;
+ this.items = new Element[size - 1];
+ }
+
+ ///
+ /// Produces a instance.
+ ///
+ /// The returned item to use.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T Allocate()
+ {
+ T? item = this.firstItem;
+
+ if (item is null || item != Interlocked.CompareExchange(ref this.firstItem, null, item))
+ {
+ item = AllocateSlow();
+ }
+
+ return item;
+ }
+
+ ///
+ /// Returns a given instance to the pool.
+ ///
+ /// The instance to return.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Free(T obj)
+ {
+ if (this.firstItem is null)
+ {
+ this.firstItem = obj;
+ }
+ else
+ {
+ FreeSlow(obj);
+ }
+ }
+
+ ///
+ /// Allocates a new item.
+ ///
+ /// The returned item to use.
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private T AllocateSlow()
+ {
+ foreach (ref Element element in this.items.AsSpan())
+ {
+ T? instance = element.Value;
+
+ if (instance is not null)
+ {
+ if (instance == Interlocked.CompareExchange(ref element.Value, null, instance))
+ {
+ return instance;
+ }
+ }
+ }
+
+ return this.factory();
+ }
+
+ ///
+ /// Frees a given item.
+ ///
+ /// The item to return to the pool.
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void FreeSlow(T obj)
+ {
+ foreach (ref Element element in this.items.AsSpan())
+ {
+ if (element.Value is null)
+ {
+ element.Value = obj;
+
+ break;
+ }
+ }
+ }
+
+ ///
+ /// A container for a produced item (using a wrapper to avoid covariance checks).
+ ///
+ private struct Element
+ {
+ ///
+ /// The value held at the current element.
+ ///
+ internal T? Value;
+ }
+}
\ No newline at end of file
diff --git a/src/PolySharp.SourceGenerators/Models/GeneratedType.cs b/src/PolySharp.SourceGenerators/Models/GeneratedType.cs
new file mode 100644
index 0000000..13a1ed3
--- /dev/null
+++ b/src/PolySharp.SourceGenerators/Models/GeneratedType.cs
@@ -0,0 +1,8 @@
+namespace PolySharp.SourceGenerators.Models;
+
+///
+/// A model to hold information on a type to generate.
+///
+/// The fully qualified type name of the type to generate.
+/// Whether to use public accessibility for the generated type.
+internal sealed record GeneratedType(string FullyQualifiedMetadataName, bool IsPublicAccessibilityRequired);
diff --git a/src/PolySharp.SourceGenerators/Models/GenerationOptions.cs b/src/PolySharp.SourceGenerators/Models/GenerationOptions.cs
new file mode 100644
index 0000000..41713c5
--- /dev/null
+++ b/src/PolySharp.SourceGenerators/Models/GenerationOptions.cs
@@ -0,0 +1,14 @@
+using PolySharp.SourceGenerators.Helpers;
+
+namespace PolySharp.SourceGenerators.Models;
+
+///
+/// A model to hold all generation options for the source generator.
+///
+/// Whether to use public accessibility for the generated types.
+/// Whether to also generated dummy runtime supported attributes.
+/// The collection of fully qualified type names of types to exclude from generation.
+internal sealed record GenerationOptions(
+ bool UsePublicAccessibilityForGeneratedTypes,
+ bool IncludeRuntimeSupportedAttributes,
+ EquatableArray ExcludeGeneratedTypes);
diff --git a/src/PolySharp.SourceGenerators/PolySharp.targets b/src/PolySharp.SourceGenerators/PolySharp.targets
index e35cab6..bece541 100644
--- a/src/PolySharp.SourceGenerators/PolySharp.targets
+++ b/src/PolySharp.SourceGenerators/PolySharp.targets
@@ -41,6 +41,7 @@
+