From ea222f8e80ef5f7addf67fbcd083ed03f913ac0b Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Thu, 4 Nov 2021 18:07:37 +0000 Subject: [PATCH 01/34] feat: Initial working sample * Created class library with 3 chainable structs * Added `IChainable` interface hierarchy * Added chaining methods `Chain`, `CreateNext`, `SetNext` and `End` * Added tests --- .gitignore | 341 +++++++++ .../.idea/.gitignore | 13 + .../.idea/encodings.xml | 4 + .../.idea/indexLayout.xml | 8 + .../.idea/vcs.xml | 6 + .../PrototypeStructChaining.Test.csproj | 29 + .../UnitTestChains.cs | 57 ++ PrototypeStructChaining.sln | 22 + PrototypeStructChaining/Bool32.cs | 62 ++ PrototypeStructChaining/IChainable.cs | 13 + ...lDeviceAccelerationStructureFeaturesKHR.cs | 60 ++ ...hysicalDeviceDescriptorIndexingFeatures.cs | 60 ++ .../PhysicalDeviceFeatures.cs | 19 + .../PhysicalDeviceFeatures2.cs | 53 ++ .../PrototypeStructChaining.csproj | 11 + PrototypeStructChaining/StructureType.cs | 704 ++++++++++++++++++ 16 files changed, 1462 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.idea.PrototypeStructChaining/.idea/.gitignore create mode 100644 .idea/.idea.PrototypeStructChaining/.idea/encodings.xml create mode 100644 .idea/.idea.PrototypeStructChaining/.idea/indexLayout.xml create mode 100644 .idea/.idea.PrototypeStructChaining/.idea/vcs.xml create mode 100644 PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj create mode 100644 PrototypeStructChaining.Test/UnitTestChains.cs create mode 100644 PrototypeStructChaining.sln create mode 100644 PrototypeStructChaining/Bool32.cs create mode 100644 PrototypeStructChaining/IChainable.cs create mode 100644 PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs create mode 100644 PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs create mode 100644 PrototypeStructChaining/PhysicalDeviceFeatures.cs create mode 100644 PrototypeStructChaining/PhysicalDeviceFeatures2.cs create mode 100644 PrototypeStructChaining/PrototypeStructChaining.csproj create mode 100644 PrototypeStructChaining/StructureType.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..a83c78113b --- /dev/null +++ b/.gitignore @@ -0,0 +1,341 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- Backup*.rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/**/workspace.xml +.idea/**/usage.statistics.xml +.idea/**/shelf/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb \ No newline at end of file diff --git a/.idea/.idea.PrototypeStructChaining/.idea/.gitignore b/.idea/.idea.PrototypeStructChaining/.idea/.gitignore new file mode 100644 index 0000000000..009550ae99 --- /dev/null +++ b/.idea/.idea.PrototypeStructChaining/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/contentModel.xml +/.idea.PrototypeStructChaining.iml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.PrototypeStructChaining/.idea/encodings.xml b/.idea/.idea.PrototypeStructChaining/.idea/encodings.xml new file mode 100644 index 0000000000..df87cf951f --- /dev/null +++ b/.idea/.idea.PrototypeStructChaining/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.PrototypeStructChaining/.idea/indexLayout.xml b/.idea/.idea.PrototypeStructChaining/.idea/indexLayout.xml new file mode 100644 index 0000000000..7b08163ceb --- /dev/null +++ b/.idea/.idea.PrototypeStructChaining/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.PrototypeStructChaining/.idea/vcs.xml b/.idea/.idea.PrototypeStructChaining/.idea/vcs.xml new file mode 100644 index 0000000000..94a25f7f4c --- /dev/null +++ b/.idea/.idea.PrototypeStructChaining/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj new file mode 100644 index 0000000000..f3281ada30 --- /dev/null +++ b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj @@ -0,0 +1,29 @@ + + + + net6.0 + enable + + false + + true + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/PrototypeStructChaining.Test/UnitTestChains.cs b/PrototypeStructChaining.Test/UnitTestChains.cs new file mode 100644 index 0000000000..0ed4f5ca5a --- /dev/null +++ b/PrototypeStructChaining.Test/UnitTestChains.cs @@ -0,0 +1,57 @@ +using Silk.Net.Vulkan; +using Xunit; + +namespace PrototypeStructChaining.Test; + +public class UnitTestChains +{ + [Fact] + public unsafe void TestCreateNext() + { + PhysicalDeviceFeatures2 + .Chain(out var features2) + .CreateNext(out var indexingFeatures) + .CreateNext(out var accelerationStructureFeaturesKhr) + .End(); + + Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); + Assert.Equal((nint) (&accelerationStructureFeaturesKhr), (nint) indexingFeatures.PNext); + Assert.Equal((nint) 0, (nint) accelerationStructureFeaturesKhr.PNext); + + Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, + accelerationStructureFeaturesKhr.SType); + } + + [Fact] + public unsafe void TestSetNext() + { + var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + { + ShaderInputAttachmentArrayDynamicIndexing = true + }; + var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKHR + { + AccelerationStructure = true + }; + + PhysicalDeviceFeatures2 + .Chain(out var features2) + .SetNext(ref indexingFeatures) + .SetNext(ref accelerationStructureFeaturesKhr) + .End(); + + Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); + Assert.Equal((nint) (&accelerationStructureFeaturesKhr), (nint) indexingFeatures.PNext); + Assert.Equal((nint) 0, (nint) accelerationStructureFeaturesKhr.PNext); + + Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, + accelerationStructureFeaturesKhr.SType); + + Assert.True(indexingFeatures.ShaderInputAttachmentArrayDynamicIndexing); + Assert.True(accelerationStructureFeaturesKhr.AccelerationStructure); + } +} \ No newline at end of file diff --git a/PrototypeStructChaining.sln b/PrototypeStructChaining.sln new file mode 100644 index 0000000000..5ffbdc6a72 --- /dev/null +++ b/PrototypeStructChaining.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrototypeStructChaining", "PrototypeStructChaining\PrototypeStructChaining.csproj", "{6EF16790-8E4E-44F1-87D6-272A85B4ACA5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrototypeStructChaining.Test", "PrototypeStructChaining.Test\PrototypeStructChaining.Test.csproj", "{29BBBD86-81DD-4A28-BABD-0B2BD37F928B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6EF16790-8E4E-44F1-87D6-272A85B4ACA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6EF16790-8E4E-44F1-87D6-272A85B4ACA5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6EF16790-8E4E-44F1-87D6-272A85B4ACA5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6EF16790-8E4E-44F1-87D6-272A85B4ACA5}.Release|Any CPU.Build.0 = Release|Any CPU + {29BBBD86-81DD-4A28-BABD-0B2BD37F928B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29BBBD86-81DD-4A28-BABD-0B2BD37F928B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29BBBD86-81DD-4A28-BABD-0B2BD37F928B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29BBBD86-81DD-4A28-BABD-0B2BD37F928B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/PrototypeStructChaining/Bool32.cs b/PrototypeStructChaining/Bool32.cs new file mode 100644 index 0000000000..8d86edd14b --- /dev/null +++ b/PrototypeStructChaining/Bool32.cs @@ -0,0 +1,62 @@ +namespace Silk.Net.Vulkan; + +/// A 32-bit boolean. +public readonly struct Bool32 +{ + /// Gets the 32-bit value for this boolean. + public uint Value { get; } + + /// + /// Creates a 32-bit boolean from the given 32-bit unsigned integer. + /// + /// The 32-bit unsigned integer value. + public Bool32(uint val) + { + Value = val; + } + + /// + /// Creates a 32-bit boolean from the given managed boolean. + /// + /// The boolean value. + public Bool32(bool val) + { + Value = val ? 1U : 0U; + } + + /// Converts this 32-bit boolean to a managed boolean. + /// The 32-bit boolean. + /// The managed boolean. + public static implicit operator bool(Bool32 val) + { + return val.Value == 1U; + } + + /// + /// Converts this 32-bit boolean to a 32-bit unsigned integer. + /// + /// The 32-bit boolean. + /// The 32-bit unsigned integer. + public static implicit operator uint(Bool32 val) + { + return val.Value; + } + + /// + /// Creates a 32-bit boolean from the given managed boolean. + /// + /// The boolean value. + public static implicit operator Bool32(bool val) + { + return new Bool32(val); + } + + /// + /// Creates a 32-bit boolean from the given 32-bit unsigned integer. + /// + /// The 32-bit unsigned integer value. + public static implicit operator Bool32(uint val) + { + return new Bool32(val); + } +} \ No newline at end of file diff --git a/PrototypeStructChaining/IChainable.cs b/PrototypeStructChaining/IChainable.cs new file mode 100644 index 0000000000..3a3d44100b --- /dev/null +++ b/PrototypeStructChaining/IChainable.cs @@ -0,0 +1,13 @@ +namespace Silk.Net.Vulkan; + +public interface IChainable +{ +} + +public interface IExtendsDeviceCreateInfoChain : IChainable +{ +} + +public interface IExtendsPhysicalDeviceFeatures2Chain : IChainable +{ +} \ No newline at end of file diff --git a/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs b/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs new file mode 100644 index 0000000000..74876ce5f7 --- /dev/null +++ b/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs @@ -0,0 +1,60 @@ +namespace Silk.Net.Vulkan; + +public struct PhysicalDeviceAccelerationStructureFeaturesKHR : IExtendsDeviceCreateInfoChain, + IExtendsPhysicalDeviceFeatures2Chain +{ + /// + public StructureType SType; + + /// + public unsafe void* PNext; + + /// + public Bool32 AccelerationStructure; + + // NOTE Truncated for example + + public unsafe PhysicalDeviceAccelerationStructureFeaturesKHR( + StructureType? sType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, + void* pNext = null, + Bool32? accelerationStructure = null) + : this() + { + if (sType.HasValue) + SType = sType.Value; + if ((IntPtr) pNext != IntPtr.Zero) + PNext = pNext; + if (accelerationStructure.HasValue) + AccelerationStructure = accelerationStructure.Value; + + // NOTE Truncated for example + } + + #region Chaining Support + public static unsafe ref PhysicalDeviceAccelerationStructureFeaturesKHR Chain(out PhysicalDeviceAccelerationStructureFeaturesKHR capture) + { + capture = new PhysicalDeviceAccelerationStructureFeaturesKHR(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr); + return ref capture; + } + + public void End() => SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; + + public unsafe ref T SetNext(ref T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + { + SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; + var reference = __makeref(capture); + PNext = (void*) *(IntPtr*) &reference; + return ref capture; + } + + public unsafe ref T CreateNext(out T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + { + SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; + capture = default; + var reference = __makeref(capture); + PNext = (void*) *(IntPtr*) &reference; + return ref capture; + } + + #endregion +} \ No newline at end of file diff --git a/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs b/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs new file mode 100644 index 0000000000..8d5f5d9238 --- /dev/null +++ b/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs @@ -0,0 +1,60 @@ +namespace Silk.Net.Vulkan; + +public struct PhysicalDeviceDescriptorIndexingFeatures : IExtendsDeviceCreateInfoChain, + IExtendsPhysicalDeviceFeatures2Chain +{ + /// + public StructureType SType; + + /// + public unsafe void* PNext; + + /// + public Bool32 ShaderInputAttachmentArrayDynamicIndexing; + + // NOTE Truncated for example + + public unsafe PhysicalDeviceDescriptorIndexingFeatures( + StructureType? sType = StructureType.PhysicalDeviceDescriptorIndexingFeaturesExt, + void* pNext = null, + Bool32? shaderInputAttachmentArrayDynamicIndexing = null) + : this() + { + if (sType.HasValue) + SType = sType.Value; + if ((IntPtr) pNext != IntPtr.Zero) + PNext = pNext; + if (shaderInputAttachmentArrayDynamicIndexing.HasValue) + ShaderInputAttachmentArrayDynamicIndexing = shaderInputAttachmentArrayDynamicIndexing.Value; + + // NOTE Truncated for example + } + + #region Chaining Support + public static unsafe ref PhysicalDeviceDescriptorIndexingFeatures Chain(out PhysicalDeviceDescriptorIndexingFeatures capture) + { + capture = new PhysicalDeviceDescriptorIndexingFeatures(StructureType.PhysicalDeviceDescriptorIndexingFeatures); + return ref capture; + } + + public void End() => SType = StructureType.PhysicalDeviceDescriptorIndexingFeatures; + + public unsafe ref T SetNext(ref T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + { + SType = StructureType.PhysicalDeviceDescriptorIndexingFeatures; + var reference = __makeref(capture); + PNext = (void*) *(IntPtr*) &reference; + return ref capture; + } + + public unsafe ref T CreateNext(out T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + { + SType = StructureType.PhysicalDeviceDescriptorIndexingFeatures; + capture = default; + var reference = __makeref(capture); + PNext = (void*) *(IntPtr*) &reference; + return ref capture; + } + + #endregion +} \ No newline at end of file diff --git a/PrototypeStructChaining/PhysicalDeviceFeatures.cs b/PrototypeStructChaining/PhysicalDeviceFeatures.cs new file mode 100644 index 0000000000..f20a4d8c8c --- /dev/null +++ b/PrototypeStructChaining/PhysicalDeviceFeatures.cs @@ -0,0 +1,19 @@ +namespace Silk.Net.Vulkan; + +public struct PhysicalDeviceFeatures +{ + /// + public Bool32 RobustBufferAccess; + + // NOTE Truncated for example + + public PhysicalDeviceFeatures( + Bool32? robustBufferAccess = null) + : this() + { + if (robustBufferAccess.HasValue) + RobustBufferAccess = robustBufferAccess.Value; + + // NOTE Truncated for example + } +} \ No newline at end of file diff --git a/PrototypeStructChaining/PhysicalDeviceFeatures2.cs b/PrototypeStructChaining/PhysicalDeviceFeatures2.cs new file mode 100644 index 0000000000..069b5c0faf --- /dev/null +++ b/PrototypeStructChaining/PhysicalDeviceFeatures2.cs @@ -0,0 +1,53 @@ +using System.Runtime.InteropServices; + +namespace Silk.Net.Vulkan; + +public struct PhysicalDeviceFeatures2 : IExtendsDeviceCreateInfoChain +{ + public StructureType SType; + public unsafe void* PNext; + public PhysicalDeviceFeatures Features; + + public unsafe PhysicalDeviceFeatures2( + StructureType? sType = StructureType.PhysicalDeviceFeatures2Khr, + void* pNext = null, + PhysicalDeviceFeatures? features = null) + : this() + { + if (sType.HasValue) + SType = sType.Value; + if ((IntPtr) pNext != IntPtr.Zero) + PNext = pNext; + if (!features.HasValue) + return; + Features = features.Value; + } + + #region Chaining Support + public static unsafe ref PhysicalDeviceFeatures2 Chain(out PhysicalDeviceFeatures2 capture) + { + capture = new PhysicalDeviceFeatures2(StructureType.PhysicalDeviceFeatures2); + return ref capture; + } + + public void End() => SType = StructureType.PhysicalDeviceFeatures2; + + public unsafe ref T SetNext(ref T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + { + SType = StructureType.PhysicalDeviceFeatures2; + var reference = __makeref(capture); + PNext = (void*) *(IntPtr*) &reference; + return ref capture; + } + + public unsafe ref T CreateNext(out T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + { + SType = StructureType.PhysicalDeviceFeatures2; + capture = default; + var reference = __makeref(capture); + PNext = (void*) *(IntPtr*) &reference; + return ref capture; + } + + #endregion +} \ No newline at end of file diff --git a/PrototypeStructChaining/PrototypeStructChaining.csproj b/PrototypeStructChaining/PrototypeStructChaining.csproj new file mode 100644 index 0000000000..211c366972 --- /dev/null +++ b/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -0,0 +1,11 @@ + + + + net6.0 + enable + enable + true + Silk.Net.Vulkan + + + diff --git a/PrototypeStructChaining/StructureType.cs b/PrototypeStructChaining/StructureType.cs new file mode 100644 index 0000000000..28a3e988f7 --- /dev/null +++ b/PrototypeStructChaining/StructureType.cs @@ -0,0 +1,704 @@ +namespace Silk.Net.Vulkan; + +public enum StructureType +{ + ApplicationInfo = 0, + InstanceCreateInfo = 1, + DeviceQueueCreateInfo = 2, + DeviceCreateInfo = 3, + SubmitInfo = 4, + MemoryAllocateInfo = 5, + MappedMemoryRange = 6, + BindSparseInfo = 7, + FenceCreateInfo = 8, + SemaphoreCreateInfo = 9, + EventCreateInfo = 10, // 0x0000000A + QueryPoolCreateInfo = 11, // 0x0000000B + BufferCreateInfo = 12, // 0x0000000C + BufferViewCreateInfo = 13, // 0x0000000D + ImageCreateInfo = 14, // 0x0000000E + ImageViewCreateInfo = 15, // 0x0000000F + ShaderModuleCreateInfo = 16, // 0x00000010 + PipelineCacheCreateInfo = 17, // 0x00000011 + PipelineShaderStageCreateInfo = 18, // 0x00000012 + PipelineVertexInputStateCreateInfo = 19, // 0x00000013 + PipelineInputAssemblyStateCreateInfo = 20, // 0x00000014 + PipelineTessellationStateCreateInfo = 21, // 0x00000015 + PipelineViewportStateCreateInfo = 22, // 0x00000016 + PipelineRasterizationStateCreateInfo = 23, // 0x00000017 + PipelineMultisampleStateCreateInfo = 24, // 0x00000018 + PipelineDepthStencilStateCreateInfo = 25, // 0x00000019 + PipelineColorBlendStateCreateInfo = 26, // 0x0000001A + PipelineDynamicStateCreateInfo = 27, // 0x0000001B + GraphicsPipelineCreateInfo = 28, // 0x0000001C + ComputePipelineCreateInfo = 29, // 0x0000001D + PipelineLayoutCreateInfo = 30, // 0x0000001E + SamplerCreateInfo = 31, // 0x0000001F + DescriptorSetLayoutCreateInfo = 32, // 0x00000020 + DescriptorPoolCreateInfo = 33, // 0x00000021 + DescriptorSetAllocateInfo = 34, // 0x00000022 + WriteDescriptorSet = 35, // 0x00000023 + CopyDescriptorSet = 36, // 0x00000024 + FramebufferCreateInfo = 37, // 0x00000025 + RenderPassCreateInfo = 38, // 0x00000026 + CommandPoolCreateInfo = 39, // 0x00000027 + CommandBufferAllocateInfo = 40, // 0x00000028 + CommandBufferInheritanceInfo = 41, // 0x00000029 + CommandBufferBeginInfo = 42, // 0x0000002A + RenderPassBeginInfo = 43, // 0x0000002B + BufferMemoryBarrier = 44, // 0x0000002C + ImageMemoryBarrier = 45, // 0x0000002D + MemoryBarrier = 46, // 0x0000002E + LoaderInstanceCreateInfo = 47, // 0x0000002F + LoaderDeviceCreateInfo = 48, // 0x00000030 + PhysicalDeviceVulkan11Features = 49, // 0x00000031 + PhysicalDeviceVulkan11Properties = 50, // 0x00000032 + PhysicalDeviceVulkan12Features = 51, // 0x00000033 + PhysicalDeviceVulkan12Properties = 52, // 0x00000034 + SwapchainCreateInfoKhr = 1000001000, // 0x3B9ACDE8 + PresentInfoKhr = 1000001001, // 0x3B9ACDE9 + DisplayModeCreateInfoKhr = 1000002000, // 0x3B9AD1D0 + DisplaySurfaceCreateInfoKhr = 1000002001, // 0x3B9AD1D1 + DisplayPresentInfoKhr = 1000003000, // 0x3B9AD5B8 + XlibSurfaceCreateInfoKhr = 1000004000, // 0x3B9AD9A0 + XcbSurfaceCreateInfoKhr = 1000005000, // 0x3B9ADD88 + WaylandSurfaceCreateInfoKhr = 1000006000, // 0x3B9AE170 + AndroidSurfaceCreateInfoKhr = 1000008000, // 0x3B9AE940 + Win32SurfaceCreateInfoKhr = 1000009000, // 0x3B9AED28 + NativeBufferAndroid = 1000010000, // 0x3B9AF110 + SwapchainImageCreateInfoAndroid = 1000010001, // 0x3B9AF111 + PhysicalDevicePresentationPropertiesAndroid = 1000010002, // 0x3B9AF112 + DebugReportCallbackCreateInfoExt = 1000011000, // 0x3B9AF4F8 + DebugReportCreateInfoExt = 1000011000, // 0x3B9AF4F8 + PipelineRasterizationStateRasterizationOrderAmd = 1000018000, // 0x3B9B1050 + DebugMarkerObjectNameInfoExt = 1000022000, // 0x3B9B1FF0 + DebugMarkerObjectTagInfoExt = 1000022001, // 0x3B9B1FF1 + DebugMarkerMarkerInfoExt = 1000022002, // 0x3B9B1FF2 + VideoProfileKhr = 1000023000, // 0x3B9B23D8 + VideoCapabilitiesKhr = 1000023001, // 0x3B9B23D9 + VideoPictureResourceKhr = 1000023002, // 0x3B9B23DA + VideoGetMemoryPropertiesKhr = 1000023003, // 0x3B9B23DB + VideoBindMemoryKhr = 1000023004, // 0x3B9B23DC + VideoSessionCreateInfoKhr = 1000023005, // 0x3B9B23DD + VideoSessionParametersCreateInfoKhr = 1000023006, // 0x3B9B23DE + VideoSessionParametersUpdateInfoKhr = 1000023007, // 0x3B9B23DF + VideoBeginCodingInfoKhr = 1000023008, // 0x3B9B23E0 + VideoEndCodingInfoKhr = 1000023009, // 0x3B9B23E1 + VideoCodingControlInfoKhr = 1000023010, // 0x3B9B23E2 + VideoReferenceSlotKhr = 1000023011, // 0x3B9B23E3 + VideoQueueFamilyProperties2Khr = 1000023012, // 0x3B9B23E4 + VideoProfilesKhr = 1000023013, // 0x3B9B23E5 + PhysicalDeviceVideoFormatInfoKhr = 1000023014, // 0x3B9B23E6 + VideoFormatPropertiesKhr = 1000023015, // 0x3B9B23E7 + VideoDecodeInfoKhr = 1000024000, // 0x3B9B27C0 + DedicatedAllocationImageCreateInfoNV = 1000026000, // 0x3B9B2F90 + DedicatedAllocationBufferCreateInfoNV = 1000026001, // 0x3B9B2F91 + DedicatedAllocationMemoryAllocateInfoNV = 1000026002, // 0x3B9B2F92 + PhysicalDeviceTransformFeedbackFeaturesExt = 1000028000, // 0x3B9B3760 + PhysicalDeviceTransformFeedbackPropertiesExt = 1000028001, // 0x3B9B3761 + PipelineRasterizationStateStreamCreateInfoExt = 1000028002, // 0x3B9B3762 + CUModuleCreateInfoNvx = 1000029000, // 0x3B9B3B48 + CUFunctionCreateInfoNvx = 1000029001, // 0x3B9B3B49 + CULaunchInfoNvx = 1000029002, // 0x3B9B3B4A + ImageViewHandleInfoNvx = 1000030000, // 0x3B9B3F30 + ImageViewAddressPropertiesNvx = 1000030001, // 0x3B9B3F31 + VideoEncodeH264CapabilitiesExt = 1000038000, // 0x3B9B5E70 + VideoEncodeH264SessionCreateInfoExt = 1000038001, // 0x3B9B5E71 + VideoEncodeH264SessionParametersCreateInfoExt = 1000038002, // 0x3B9B5E72 + VideoEncodeH264SessionParametersAddInfoExt = 1000038003, // 0x3B9B5E73 + VideoEncodeH264VclFrameInfoExt = 1000038004, // 0x3B9B5E74 + VideoEncodeH264DpbSlotInfoExt = 1000038005, // 0x3B9B5E75 + VideoEncodeH264NaluSliceExt = 1000038006, // 0x3B9B5E76 + VideoEncodeH264EmitPictureParametersExt = 1000038007, // 0x3B9B5E77 + VideoEncodeH264ProfileExt = 1000038008, // 0x3B9B5E78 + VideoDecodeH264CapabilitiesExt = 1000040000, // 0x3B9B6640 + VideoDecodeH264SessionCreateInfoExt = 1000040001, // 0x3B9B6641 + VideoDecodeH264PictureInfoExt = 1000040002, // 0x3B9B6642 + VideoDecodeH264MvcExt = 1000040003, // 0x3B9B6643 + VideoDecodeH264ProfileExt = 1000040004, // 0x3B9B6644 + VideoDecodeH264SessionParametersCreateInfoExt = 1000040005, // 0x3B9B6645 + VideoDecodeH264SessionParametersAddInfoExt = 1000040006, // 0x3B9B6646 + VideoDecodeH264DpbSlotInfoExt = 1000040007, // 0x3B9B6647 + TextureLodGatherFormatPropertiesAmd = 1000041000, // 0x3B9B6A28 + StreamDescriptorSurfaceCreateInfoGgp = 1000049000, // 0x3B9B8968 + PhysicalDeviceCornerSampledImageFeaturesNV = 1000050000, // 0x3B9B8D50 + RenderPassMultiviewCreateInfo = 1000053000, // 0x3B9B9908 + RenderPassMultiviewCreateInfoKhr = 1000053000, // 0x3B9B9908 + PhysicalDeviceMultiviewFeatures = 1000053001, // 0x3B9B9909 + PhysicalDeviceMultiviewFeaturesKhr = 1000053001, // 0x3B9B9909 + PhysicalDeviceMultiviewProperties = 1000053002, // 0x3B9B990A + PhysicalDeviceMultiviewPropertiesKhr = 1000053002, // 0x3B9B990A + ExternalMemoryImageCreateInfoNV = 1000056000, // 0x3B9BA4C0 + ExportMemoryAllocateInfoNV = 1000056001, // 0x3B9BA4C1 + ImportMemoryWin32HandleInfoNV = 1000057000, // 0x3B9BA8A8 + ExportMemoryWin32HandleInfoNV = 1000057001, // 0x3B9BA8A9 + Win32KeyedMutexAcquireReleaseInfoNV = 1000058000, // 0x3B9BAC90 + PhysicalDeviceFeatures2 = 1000059000, // 0x3B9BB078 + PhysicalDeviceFeatures2Khr = 1000059000, // 0x3B9BB078 + PhysicalDeviceProperties2 = 1000059001, // 0x3B9BB079 + PhysicalDeviceProperties2Khr = 1000059001, // 0x3B9BB079 + FormatProperties2 = 1000059002, // 0x3B9BB07A + FormatProperties2Khr = 1000059002, // 0x3B9BB07A + ImageFormatProperties2 = 1000059003, // 0x3B9BB07B + ImageFormatProperties2Khr = 1000059003, // 0x3B9BB07B + PhysicalDeviceImageFormatInfo2 = 1000059004, // 0x3B9BB07C + PhysicalDeviceImageFormatInfo2Khr = 1000059004, // 0x3B9BB07C + QueueFamilyProperties2 = 1000059005, // 0x3B9BB07D + QueueFamilyProperties2Khr = 1000059005, // 0x3B9BB07D + PhysicalDeviceMemoryProperties2 = 1000059006, // 0x3B9BB07E + PhysicalDeviceMemoryProperties2Khr = 1000059006, // 0x3B9BB07E + SparseImageFormatProperties2 = 1000059007, // 0x3B9BB07F + SparseImageFormatProperties2Khr = 1000059007, // 0x3B9BB07F + PhysicalDeviceSparseImageFormatInfo2 = 1000059008, // 0x3B9BB080 + PhysicalDeviceSparseImageFormatInfo2Khr = 1000059008, // 0x3B9BB080 + MemoryAllocateFlagsInfo = 1000060000, // 0x3B9BB460 + MemoryAllocateFlagsInfoKhr = 1000060000, // 0x3B9BB460 + DeviceGroupRenderPassBeginInfo = 1000060003, // 0x3B9BB463 + DeviceGroupRenderPassBeginInfoKhr = 1000060003, // 0x3B9BB463 + DeviceGroupCommandBufferBeginInfo = 1000060004, // 0x3B9BB464 + DeviceGroupCommandBufferBeginInfoKhr = 1000060004, // 0x3B9BB464 + DeviceGroupSubmitInfo = 1000060005, // 0x3B9BB465 + DeviceGroupSubmitInfoKhr = 1000060005, // 0x3B9BB465 + DeviceGroupBindSparseInfo = 1000060006, // 0x3B9BB466 + DeviceGroupBindSparseInfoKhr = 1000060006, // 0x3B9BB466 + DeviceGroupPresentCapabilitiesKhr = 1000060007, // 0x3B9BB467 + ImageSwapchainCreateInfoKhr = 1000060008, // 0x3B9BB468 + BindImageMemorySwapchainInfoKhr = 1000060009, // 0x3B9BB469 + AcquireNextImageInfoKhr = 1000060010, // 0x3B9BB46A + DeviceGroupPresentInfoKhr = 1000060011, // 0x3B9BB46B + DeviceGroupSwapchainCreateInfoKhr = 1000060012, // 0x3B9BB46C + BindBufferMemoryDeviceGroupInfo = 1000060013, // 0x3B9BB46D + BindBufferMemoryDeviceGroupInfoKhr = 1000060013, // 0x3B9BB46D + BindImageMemoryDeviceGroupInfo = 1000060014, // 0x3B9BB46E + BindImageMemoryDeviceGroupInfoKhr = 1000060014, // 0x3B9BB46E + ValidationFlagsExt = 1000061000, // 0x3B9BB848 + VISurfaceCreateInfoNN = 1000062000, // 0x3B9BBC30 + PhysicalDeviceShaderDrawParameterFeatures = 1000063000, // 0x3B9BC018 + PhysicalDeviceShaderDrawParametersFeatures = 1000063000, // 0x3B9BC018 + PhysicalDeviceTextureCompressionAstcHdrFeaturesExt = 1000066000, // 0x3B9BCBD0 + ImageViewAstcDecodeModeExt = 1000067000, // 0x3B9BCFB8 + PhysicalDeviceAstcDecodeFeaturesExt = 1000067001, // 0x3B9BCFB9 + PhysicalDeviceGroupProperties = 1000070000, // 0x3B9BDB70 + PhysicalDeviceGroupPropertiesKhr = 1000070000, // 0x3B9BDB70 + DeviceGroupDeviceCreateInfo = 1000070001, // 0x3B9BDB71 + DeviceGroupDeviceCreateInfoKhr = 1000070001, // 0x3B9BDB71 + PhysicalDeviceExternalImageFormatInfo = 1000071000, // 0x3B9BDF58 + PhysicalDeviceExternalImageFormatInfoKhr = 1000071000, // 0x3B9BDF58 + ExternalImageFormatProperties = 1000071001, // 0x3B9BDF59 + ExternalImageFormatPropertiesKhr = 1000071001, // 0x3B9BDF59 + PhysicalDeviceExternalBufferInfo = 1000071002, // 0x3B9BDF5A + PhysicalDeviceExternalBufferInfoKhr = 1000071002, // 0x3B9BDF5A + ExternalBufferProperties = 1000071003, // 0x3B9BDF5B + ExternalBufferPropertiesKhr = 1000071003, // 0x3B9BDF5B + PhysicalDeviceIDProperties = 1000071004, // 0x3B9BDF5C + PhysicalDeviceIDPropertiesKhr = 1000071004, // 0x3B9BDF5C + ExternalMemoryBufferCreateInfo = 1000072000, // 0x3B9BE340 + ExternalMemoryBufferCreateInfoKhr = 1000072000, // 0x3B9BE340 + ExternalMemoryImageCreateInfo = 1000072001, // 0x3B9BE341 + ExternalMemoryImageCreateInfoKhr = 1000072001, // 0x3B9BE341 + ExportMemoryAllocateInfo = 1000072002, // 0x3B9BE342 + ExportMemoryAllocateInfoKhr = 1000072002, // 0x3B9BE342 + ImportMemoryWin32HandleInfoKhr = 1000073000, // 0x3B9BE728 + ExportMemoryWin32HandleInfoKhr = 1000073001, // 0x3B9BE729 + MemoryWin32HandlePropertiesKhr = 1000073002, // 0x3B9BE72A + MemoryGetWin32HandleInfoKhr = 1000073003, // 0x3B9BE72B + ImportMemoryFDInfoKhr = 1000074000, // 0x3B9BEB10 + MemoryFDPropertiesKhr = 1000074001, // 0x3B9BEB11 + MemoryGetFDInfoKhr = 1000074002, // 0x3B9BEB12 + Win32KeyedMutexAcquireReleaseInfoKhr = 1000075000, // 0x3B9BEEF8 + PhysicalDeviceExternalSemaphoreInfo = 1000076000, // 0x3B9BF2E0 + PhysicalDeviceExternalSemaphoreInfoKhr = 1000076000, // 0x3B9BF2E0 + ExternalSemaphoreProperties = 1000076001, // 0x3B9BF2E1 + ExternalSemaphorePropertiesKhr = 1000076001, // 0x3B9BF2E1 + ExportSemaphoreCreateInfo = 1000077000, // 0x3B9BF6C8 + ExportSemaphoreCreateInfoKhr = 1000077000, // 0x3B9BF6C8 + ImportSemaphoreWin32HandleInfoKhr = 1000078000, // 0x3B9BFAB0 + ExportSemaphoreWin32HandleInfoKhr = 1000078001, // 0x3B9BFAB1 + D3D12FenceSubmitInfoKhr = 1000078002, // 0x3B9BFAB2 + SemaphoreGetWin32HandleInfoKhr = 1000078003, // 0x3B9BFAB3 + ImportSemaphoreFDInfoKhr = 1000079000, // 0x3B9BFE98 + SemaphoreGetFDInfoKhr = 1000079001, // 0x3B9BFE99 + PhysicalDevicePushDescriptorPropertiesKhr = 1000080000, // 0x3B9C0280 + CommandBufferInheritanceConditionalRenderingInfoExt = 1000081000, // 0x3B9C0668 + PhysicalDeviceConditionalRenderingFeaturesExt = 1000081001, // 0x3B9C0669 + ConditionalRenderingBeginInfoExt = 1000081002, // 0x3B9C066A + PhysicalDeviceFloat16Int8FeaturesKhr = 1000082000, // 0x3B9C0A50 + PhysicalDeviceShaderFloat16Int8Features = 1000082000, // 0x3B9C0A50 + PhysicalDeviceShaderFloat16Int8FeaturesKhr = 1000082000, // 0x3B9C0A50 + PhysicalDevice16BitStorageFeatures = 1000083000, // 0x3B9C0E38 + PhysicalDevice16BitStorageFeaturesKhr = 1000083000, // 0x3B9C0E38 + PresentRegionsKhr = 1000084000, // 0x3B9C1220 + DescriptorUpdateTemplateCreateInfo = 1000085000, // 0x3B9C1608 + DescriptorUpdateTemplateCreateInfoKhr = 1000085000, // 0x3B9C1608 + PipelineViewportWScalingStateCreateInfoNV = 1000087000, // 0x3B9C1DD8 + SurfaceCapabilities2Ext = 1000090000, // 0x3B9C2990 + DisplayPowerInfoExt = 1000091000, // 0x3B9C2D78 + DeviceEventInfoExt = 1000091001, // 0x3B9C2D79 + DisplayEventInfoExt = 1000091002, // 0x3B9C2D7A + SwapchainCounterCreateInfoExt = 1000091003, // 0x3B9C2D7B + PresentTimesInfoGoogle = 1000092000, // 0x3B9C3160 + PhysicalDeviceSubgroupProperties = 1000094000, // 0x3B9C3930 + PhysicalDeviceMultiviewPerViewAttributesPropertiesNvx = 1000097000, // 0x3B9C44E8 + PipelineViewportSwizzleStateCreateInfoNV = 1000098000, // 0x3B9C48D0 + PhysicalDeviceDiscardRectanglePropertiesExt = 1000099000, // 0x3B9C4CB8 + PipelineDiscardRectangleStateCreateInfoExt = 1000099001, // 0x3B9C4CB9 + PhysicalDeviceConservativeRasterizationPropertiesExt = 1000101000, // 0x3B9C5488 + PipelineRasterizationConservativeStateCreateInfoExt = 1000101001, // 0x3B9C5489 + PhysicalDeviceDepthClipEnableFeaturesExt = 1000102000, // 0x3B9C5870 + PipelineRasterizationDepthClipStateCreateInfoExt = 1000102001, // 0x3B9C5871 + HdrMetadataExt = 1000105000, // 0x3B9C6428 + PhysicalDeviceImagelessFramebufferFeatures = 1000108000, // 0x3B9C6FE0 + PhysicalDeviceImagelessFramebufferFeaturesKhr = 1000108000, // 0x3B9C6FE0 + FramebufferAttachmentsCreateInfo = 1000108001, // 0x3B9C6FE1 + FramebufferAttachmentsCreateInfoKhr = 1000108001, // 0x3B9C6FE1 + FramebufferAttachmentImageInfo = 1000108002, // 0x3B9C6FE2 + FramebufferAttachmentImageInfoKhr = 1000108002, // 0x3B9C6FE2 + RenderPassAttachmentBeginInfo = 1000108003, // 0x3B9C6FE3 + RenderPassAttachmentBeginInfoKhr = 1000108003, // 0x3B9C6FE3 + AttachmentDescription2 = 1000109000, // 0x3B9C73C8 + AttachmentDescription2Khr = 1000109000, // 0x3B9C73C8 + AttachmentReference2 = 1000109001, // 0x3B9C73C9 + AttachmentReference2Khr = 1000109001, // 0x3B9C73C9 + SubpassDescription2 = 1000109002, // 0x3B9C73CA + SubpassDescription2Khr = 1000109002, // 0x3B9C73CA + SubpassDependency2 = 1000109003, // 0x3B9C73CB + SubpassDependency2Khr = 1000109003, // 0x3B9C73CB + RenderPassCreateInfo2 = 1000109004, // 0x3B9C73CC + RenderPassCreateInfo2Khr = 1000109004, // 0x3B9C73CC + SubpassBeginInfo = 1000109005, // 0x3B9C73CD + SubpassBeginInfoKhr = 1000109005, // 0x3B9C73CD + SubpassEndInfo = 1000109006, // 0x3B9C73CE + SubpassEndInfoKhr = 1000109006, // 0x3B9C73CE + SharedPresentSurfaceCapabilitiesKhr = 1000111000, // 0x3B9C7B98 + PhysicalDeviceExternalFenceInfo = 1000112000, // 0x3B9C7F80 + PhysicalDeviceExternalFenceInfoKhr = 1000112000, // 0x3B9C7F80 + ExternalFenceProperties = 1000112001, // 0x3B9C7F81 + ExternalFencePropertiesKhr = 1000112001, // 0x3B9C7F81 + ExportFenceCreateInfo = 1000113000, // 0x3B9C8368 + ExportFenceCreateInfoKhr = 1000113000, // 0x3B9C8368 + ImportFenceWin32HandleInfoKhr = 1000114000, // 0x3B9C8750 + ExportFenceWin32HandleInfoKhr = 1000114001, // 0x3B9C8751 + FenceGetWin32HandleInfoKhr = 1000114002, // 0x3B9C8752 + ImportFenceFDInfoKhr = 1000115000, // 0x3B9C8B38 + FenceGetFDInfoKhr = 1000115001, // 0x3B9C8B39 + PhysicalDevicePerformanceQueryFeaturesKhr = 1000116000, // 0x3B9C8F20 + PhysicalDevicePerformanceQueryPropertiesKhr = 1000116001, // 0x3B9C8F21 + QueryPoolPerformanceCreateInfoKhr = 1000116002, // 0x3B9C8F22 + PerformanceQuerySubmitInfoKhr = 1000116003, // 0x3B9C8F23 + AcquireProfilingLockInfoKhr = 1000116004, // 0x3B9C8F24 + PerformanceCounterKhr = 1000116005, // 0x3B9C8F25 + PerformanceCounterDescriptionKhr = 1000116006, // 0x3B9C8F26 + PhysicalDevicePointClippingProperties = 1000117000, // 0x3B9C9308 + PhysicalDevicePointClippingPropertiesKhr = 1000117000, // 0x3B9C9308 + RenderPassInputAttachmentAspectCreateInfo = 1000117001, // 0x3B9C9309 + RenderPassInputAttachmentAspectCreateInfoKhr = 1000117001, // 0x3B9C9309 + ImageViewUsageCreateInfo = 1000117002, // 0x3B9C930A + ImageViewUsageCreateInfoKhr = 1000117002, // 0x3B9C930A + PipelineTessellationDomainOriginStateCreateInfo = 1000117003, // 0x3B9C930B + PipelineTessellationDomainOriginStateCreateInfoKhr = 1000117003, // 0x3B9C930B + PhysicalDeviceSurfaceInfo2Khr = 1000119000, // 0x3B9C9AD8 + SurfaceCapabilities2Khr = 1000119001, // 0x3B9C9AD9 + SurfaceFormat2Khr = 1000119002, // 0x3B9C9ADA + PhysicalDeviceVariablePointerFeatures = 1000120000, // 0x3B9C9EC0 + PhysicalDeviceVariablePointerFeaturesKhr = 1000120000, // 0x3B9C9EC0 + PhysicalDeviceVariablePointersFeatures = 1000120000, // 0x3B9C9EC0 + PhysicalDeviceVariablePointersFeaturesKhr = 1000120000, // 0x3B9C9EC0 + DisplayProperties2Khr = 1000121000, // 0x3B9CA2A8 + DisplayPlaneProperties2Khr = 1000121001, // 0x3B9CA2A9 + DisplayModeProperties2Khr = 1000121002, // 0x3B9CA2AA + DisplayPlaneInfo2Khr = 1000121003, // 0x3B9CA2AB + DisplayPlaneCapabilities2Khr = 1000121004, // 0x3B9CA2AC + IosSurfaceCreateInfoMvk = 1000122000, // 0x3B9CA690 + MacosSurfaceCreateInfoMvk = 1000123000, // 0x3B9CAA78 + MemoryDedicatedRequirements = 1000127000, // 0x3B9CBA18 + MemoryDedicatedRequirementsKhr = 1000127000, // 0x3B9CBA18 + MemoryDedicatedAllocateInfo = 1000127001, // 0x3B9CBA19 + MemoryDedicatedAllocateInfoKhr = 1000127001, // 0x3B9CBA19 + DebugUtilsObjectNameInfoExt = 1000128000, // 0x3B9CBE00 + DebugUtilsObjectTagInfoExt = 1000128001, // 0x3B9CBE01 + DebugUtilsLabelExt = 1000128002, // 0x3B9CBE02 + DebugUtilsMessengerCallbackDataExt = 1000128003, // 0x3B9CBE03 + DebugUtilsMessengerCreateInfoExt = 1000128004, // 0x3B9CBE04 + AndroidHardwareBufferUsageAndroid = 1000129000, // 0x3B9CC1E8 + AndroidHardwareBufferPropertiesAndroid = 1000129001, // 0x3B9CC1E9 + AndroidHardwareBufferFormatPropertiesAndroid = 1000129002, // 0x3B9CC1EA + ImportAndroidHardwareBufferInfoAndroid = 1000129003, // 0x3B9CC1EB + MemoryGetAndroidHardwareBufferInfoAndroid = 1000129004, // 0x3B9CC1EC + ExternalFormatAndroid = 1000129005, // 0x3B9CC1ED + PhysicalDeviceSamplerFilterMinmaxProperties = 1000130000, // 0x3B9CC5D0 + PhysicalDeviceSamplerFilterMinmaxPropertiesExt = 1000130000, // 0x3B9CC5D0 + SamplerReductionModeCreateInfo = 1000130001, // 0x3B9CC5D1 + SamplerReductionModeCreateInfoExt = 1000130001, // 0x3B9CC5D1 + PhysicalDeviceInlineUniformBlockFeaturesExt = 1000138000, // 0x3B9CE510 + PhysicalDeviceInlineUniformBlockPropertiesExt = 1000138001, // 0x3B9CE511 + WriteDescriptorSetInlineUniformBlockExt = 1000138002, // 0x3B9CE512 + DescriptorPoolInlineUniformBlockCreateInfoExt = 1000138003, // 0x3B9CE513 + SampleLocationsInfoExt = 1000143000, // 0x3B9CF898 + RenderPassSampleLocationsBeginInfoExt = 1000143001, // 0x3B9CF899 + PipelineSampleLocationsStateCreateInfoExt = 1000143002, // 0x3B9CF89A + PhysicalDeviceSampleLocationsPropertiesExt = 1000143003, // 0x3B9CF89B + MultisamplePropertiesExt = 1000143004, // 0x3B9CF89C + ProtectedSubmitInfo = 1000145000, // 0x3B9D0068 + PhysicalDeviceProtectedMemoryFeatures = 1000145001, // 0x3B9D0069 + PhysicalDeviceProtectedMemoryProperties = 1000145002, // 0x3B9D006A + DeviceQueueInfo2 = 1000145003, // 0x3B9D006B + BufferMemoryRequirementsInfo2 = 1000146000, // 0x3B9D0450 + BufferMemoryRequirementsInfo2Khr = 1000146000, // 0x3B9D0450 + ImageMemoryRequirementsInfo2 = 1000146001, // 0x3B9D0451 + ImageMemoryRequirementsInfo2Khr = 1000146001, // 0x3B9D0451 + ImageSparseMemoryRequirementsInfo2 = 1000146002, // 0x3B9D0452 + ImageSparseMemoryRequirementsInfo2Khr = 1000146002, // 0x3B9D0452 + MemoryRequirements2 = 1000146003, // 0x3B9D0453 + MemoryRequirements2Khr = 1000146003, // 0x3B9D0453 + SparseImageMemoryRequirements2 = 1000146004, // 0x3B9D0454 + SparseImageMemoryRequirements2Khr = 1000146004, // 0x3B9D0454 + ImageFormatListCreateInfo = 1000147000, // 0x3B9D0838 + ImageFormatListCreateInfoKhr = 1000147000, // 0x3B9D0838 + PhysicalDeviceBlendOperationAdvancedFeaturesExt = 1000148000, // 0x3B9D0C20 + PhysicalDeviceBlendOperationAdvancedPropertiesExt = 1000148001, // 0x3B9D0C21 + PipelineColorBlendAdvancedStateCreateInfoExt = 1000148002, // 0x3B9D0C22 + PipelineCoverageToColorStateCreateInfoNV = 1000149000, // 0x3B9D1008 + AccelerationStructureBuildGeometryInfoKhr = 1000150000, // 0x3B9D13F0 + AccelerationStructureDeviceAddressInfoKhr = 1000150002, // 0x3B9D13F2 + AccelerationStructureGeometryAabbsDataKhr = 1000150003, // 0x3B9D13F3 + AccelerationStructureGeometryInstancesDataKhr = 1000150004, // 0x3B9D13F4 + AccelerationStructureGeometryTrianglesDataKhr = 1000150005, // 0x3B9D13F5 + AccelerationStructureGeometryKhr = 1000150006, // 0x3B9D13F6 + WriteDescriptorSetAccelerationStructureKhr = 1000150007, // 0x3B9D13F7 + AccelerationStructureVersionInfoKhr = 1000150009, // 0x3B9D13F9 + CopyAccelerationStructureInfoKhr = 1000150010, // 0x3B9D13FA + CopyAccelerationStructureToMemoryInfoKhr = 1000150011, // 0x3B9D13FB + CopyMemoryToAccelerationStructureInfoKhr = 1000150012, // 0x3B9D13FC + PhysicalDeviceAccelerationStructureFeaturesKhr = 1000150013, // 0x3B9D13FD + PhysicalDeviceAccelerationStructurePropertiesKhr = 1000150014, // 0x3B9D13FE + RayTracingPipelineCreateInfoKhr = 1000150015, // 0x3B9D13FF + RayTracingShaderGroupCreateInfoKhr = 1000150016, // 0x3B9D1400 + AccelerationStructureCreateInfoKhr = 1000150017, // 0x3B9D1401 + RayTracingPipelineInterfaceCreateInfoKhr = 1000150018, // 0x3B9D1402 + AccelerationStructureBuildSizesInfoKhr = 1000150020, // 0x3B9D1404 + PipelineCoverageModulationStateCreateInfoNV = 1000152000, // 0x3B9D1BC0 + PhysicalDeviceShaderSMBuiltinsFeaturesNV = 1000154000, // 0x3B9D2390 + PhysicalDeviceShaderSMBuiltinsPropertiesNV = 1000154001, // 0x3B9D2391 + SamplerYcbcrConversionCreateInfo = 1000156000, // 0x3B9D2B60 + SamplerYcbcrConversionCreateInfoKhr = 1000156000, // 0x3B9D2B60 + SamplerYcbcrConversionInfo = 1000156001, // 0x3B9D2B61 + SamplerYcbcrConversionInfoKhr = 1000156001, // 0x3B9D2B61 + BindImagePlaneMemoryInfo = 1000156002, // 0x3B9D2B62 + BindImagePlaneMemoryInfoKhr = 1000156002, // 0x3B9D2B62 + ImagePlaneMemoryRequirementsInfo = 1000156003, // 0x3B9D2B63 + ImagePlaneMemoryRequirementsInfoKhr = 1000156003, // 0x3B9D2B63 + PhysicalDeviceSamplerYcbcrConversionFeatures = 1000156004, // 0x3B9D2B64 + PhysicalDeviceSamplerYcbcrConversionFeaturesKhr = 1000156004, // 0x3B9D2B64 + SamplerYcbcrConversionImageFormatProperties = 1000156005, // 0x3B9D2B65 + SamplerYcbcrConversionImageFormatPropertiesKhr = 1000156005, // 0x3B9D2B65 + BindBufferMemoryInfo = 1000157000, // 0x3B9D2F48 + BindBufferMemoryInfoKhr = 1000157000, // 0x3B9D2F48 + BindImageMemoryInfo = 1000157001, // 0x3B9D2F49 + BindImageMemoryInfoKhr = 1000157001, // 0x3B9D2F49 + DrmFormatModifierPropertiesListExt = 1000158000, // 0x3B9D3330 + PhysicalDeviceImageDrmFormatModifierInfoExt = 1000158002, // 0x3B9D3332 + ImageDrmFormatModifierListCreateInfoExt = 1000158003, // 0x3B9D3333 + ImageDrmFormatModifierExplicitCreateInfoExt = 1000158004, // 0x3B9D3334 + ImageDrmFormatModifierPropertiesExt = 1000158005, // 0x3B9D3335 + ValidationCacheCreateInfoExt = 1000160000, // 0x3B9D3B00 + ShaderModuleValidationCacheCreateInfoExt = 1000160001, // 0x3B9D3B01 + DescriptorSetLayoutBindingFlagsCreateInfo = 1000161000, // 0x3B9D3EE8 + DescriptorSetLayoutBindingFlagsCreateInfoExt = 1000161000, // 0x3B9D3EE8 + PhysicalDeviceDescriptorIndexingFeatures = 1000161001, // 0x3B9D3EE9 + PhysicalDeviceDescriptorIndexingFeaturesExt = 1000161001, // 0x3B9D3EE9 + PhysicalDeviceDescriptorIndexingProperties = 1000161002, // 0x3B9D3EEA + PhysicalDeviceDescriptorIndexingPropertiesExt = 1000161002, // 0x3B9D3EEA + DescriptorSetVariableDescriptorCountAllocateInfo = 1000161003, // 0x3B9D3EEB + DescriptorSetVariableDescriptorCountAllocateInfoExt = 1000161003, // 0x3B9D3EEB + DescriptorSetVariableDescriptorCountLayoutSupport = 1000161004, // 0x3B9D3EEC + DescriptorSetVariableDescriptorCountLayoutSupportExt = 1000161004, // 0x3B9D3EEC + PhysicalDevicePortabilitySubsetFeaturesKhr = 1000163000, // 0x3B9D46B8 + PhysicalDevicePortabilitySubsetPropertiesKhr = 1000163001, // 0x3B9D46B9 + PipelineViewportShadingRateImageStateCreateInfoNV = 1000164000, // 0x3B9D4AA0 + PhysicalDeviceShadingRateImageFeaturesNV = 1000164001, // 0x3B9D4AA1 + PhysicalDeviceShadingRateImagePropertiesNV = 1000164002, // 0x3B9D4AA2 + PipelineViewportCoarseSampleOrderStateCreateInfoNV = 1000164005, // 0x3B9D4AA5 + RayTracingPipelineCreateInfoNV = 1000165000, // 0x3B9D4E88 + AccelerationStructureCreateInfoNV = 1000165001, // 0x3B9D4E89 + GeometryNV = 1000165003, // 0x3B9D4E8B + GeometryTrianglesNV = 1000165004, // 0x3B9D4E8C + GeometryAabbNV = 1000165005, // 0x3B9D4E8D + BindAccelerationStructureMemoryInfoNV = 1000165006, // 0x3B9D4E8E + WriteDescriptorSetAccelerationStructureNV = 1000165007, // 0x3B9D4E8F + AccelerationStructureMemoryRequirementsInfoNV = 1000165008, // 0x3B9D4E90 + PhysicalDeviceRayTracingPropertiesNV = 1000165009, // 0x3B9D4E91 + RayTracingShaderGroupCreateInfoNV = 1000165011, // 0x3B9D4E93 + AccelerationStructureInfoNV = 1000165012, // 0x3B9D4E94 + PhysicalDeviceRepresentativeFragmentTestFeaturesNV = 1000166000, // 0x3B9D5270 + PipelineRepresentativeFragmentTestStateCreateInfoNV = 1000166001, // 0x3B9D5271 + PhysicalDeviceMaintenance3Properties = 1000168000, // 0x3B9D5A40 + PhysicalDeviceMaintenance3PropertiesKhr = 1000168000, // 0x3B9D5A40 + DescriptorSetLayoutSupport = 1000168001, // 0x3B9D5A41 + DescriptorSetLayoutSupportKhr = 1000168001, // 0x3B9D5A41 + PhysicalDeviceImageViewImageFormatInfoExt = 1000170000, // 0x3B9D6210 + FilterCubicImageViewImageFormatPropertiesExt = 1000170001, // 0x3B9D6211 + DeviceQueueGlobalPriorityCreateInfoExt = 1000174000, // 0x3B9D71B0 + PhysicalDeviceShaderSubgroupExtendedTypesFeatures = 1000175000, // 0x3B9D7598 + PhysicalDeviceShaderSubgroupExtendedTypesFeaturesKhr = 1000175000, // 0x3B9D7598 + PhysicalDevice8BitStorageFeatures = 1000177000, // 0x3B9D7D68 + PhysicalDevice8BitStorageFeaturesKhr = 1000177000, // 0x3B9D7D68 + ImportMemoryHostPointerInfoExt = 1000178000, // 0x3B9D8150 + MemoryHostPointerPropertiesExt = 1000178001, // 0x3B9D8151 + PhysicalDeviceExternalMemoryHostPropertiesExt = 1000178002, // 0x3B9D8152 + PhysicalDeviceShaderAtomicInt64Features = 1000180000, // 0x3B9D8920 + PhysicalDeviceShaderAtomicInt64FeaturesKhr = 1000180000, // 0x3B9D8920 + PhysicalDeviceShaderClockFeaturesKhr = 1000181000, // 0x3B9D8D08 + PipelineCompilerControlCreateInfoAmd = 1000183000, // 0x3B9D94D8 + CalibratedTimestampInfoExt = 1000184000, // 0x3B9D98C0 + PhysicalDeviceShaderCorePropertiesAmd = 1000185000, // 0x3B9D9CA8 + VideoDecodeH265CapabilitiesExt = 1000187000, // 0x3B9DA478 + VideoDecodeH265SessionCreateInfoExt = 1000187001, // 0x3B9DA479 + VideoDecodeH265SessionParametersCreateInfoExt = 1000187002, // 0x3B9DA47A + VideoDecodeH265SessionParametersAddInfoExt = 1000187003, // 0x3B9DA47B + VideoDecodeH265ProfileExt = 1000187004, // 0x3B9DA47C + VideoDecodeH265PictureInfoExt = 1000187005, // 0x3B9DA47D + VideoDecodeH265DpbSlotInfoExt = 1000187006, // 0x3B9DA47E + DeviceMemoryOverallocationCreateInfoAmd = 1000189000, // 0x3B9DAC48 + PhysicalDeviceVertexAttributeDivisorPropertiesExt = 1000190000, // 0x3B9DB030 + PipelineVertexInputDivisorStateCreateInfoExt = 1000190001, // 0x3B9DB031 + PhysicalDeviceVertexAttributeDivisorFeaturesExt = 1000190002, // 0x3B9DB032 + PresentFrameTokenGgp = 1000191000, // 0x3B9DB418 + PipelineCreationFeedbackCreateInfoExt = 1000192000, // 0x3B9DB800 + PhysicalDeviceDriverProperties = 1000196000, // 0x3B9DC7A0 + PhysicalDeviceDriverPropertiesKhr = 1000196000, // 0x3B9DC7A0 + PhysicalDeviceFloatControlsProperties = 1000197000, // 0x3B9DCB88 + PhysicalDeviceFloatControlsPropertiesKhr = 1000197000, // 0x3B9DCB88 + PhysicalDeviceDepthStencilResolveProperties = 1000199000, // 0x3B9DD358 + PhysicalDeviceDepthStencilResolvePropertiesKhr = 1000199000, // 0x3B9DD358 + SubpassDescriptionDepthStencilResolve = 1000199001, // 0x3B9DD359 + SubpassDescriptionDepthStencilResolveKhr = 1000199001, // 0x3B9DD359 + PhysicalDeviceComputeShaderDerivativesFeaturesNV = 1000201000, // 0x3B9DDB28 + PhysicalDeviceMeshShaderFeaturesNV = 1000202000, // 0x3B9DDF10 + PhysicalDeviceMeshShaderPropertiesNV = 1000202001, // 0x3B9DDF11 + PhysicalDeviceFragmentShaderBarycentricFeaturesNV = 1000203000, // 0x3B9DE2F8 + PhysicalDeviceShaderImageFootprintFeaturesNV = 1000204000, // 0x3B9DE6E0 + PipelineViewportExclusiveScissorStateCreateInfoNV = 1000205000, // 0x3B9DEAC8 + PhysicalDeviceExclusiveScissorFeaturesNV = 1000205002, // 0x3B9DEACA + CheckpointDataNV = 1000206000, // 0x3B9DEEB0 + QueueFamilyCheckpointPropertiesNV = 1000206001, // 0x3B9DEEB1 + PhysicalDeviceTimelineSemaphoreFeatures = 1000207000, // 0x3B9DF298 + PhysicalDeviceTimelineSemaphoreFeaturesKhr = 1000207000, // 0x3B9DF298 + PhysicalDeviceTimelineSemaphoreProperties = 1000207001, // 0x3B9DF299 + PhysicalDeviceTimelineSemaphorePropertiesKhr = 1000207001, // 0x3B9DF299 + SemaphoreTypeCreateInfo = 1000207002, // 0x3B9DF29A + SemaphoreTypeCreateInfoKhr = 1000207002, // 0x3B9DF29A + TimelineSemaphoreSubmitInfo = 1000207003, // 0x3B9DF29B + TimelineSemaphoreSubmitInfoKhr = 1000207003, // 0x3B9DF29B + SemaphoreWaitInfo = 1000207004, // 0x3B9DF29C + SemaphoreWaitInfoKhr = 1000207004, // 0x3B9DF29C + SemaphoreSignalInfo = 1000207005, // 0x3B9DF29D + SemaphoreSignalInfoKhr = 1000207005, // 0x3B9DF29D + PhysicalDeviceShaderIntegerFunctions2FeaturesIntel = 1000209000, // 0x3B9DFA68 + QueryPoolCreateInfoIntel = 1000210000, // 0x3B9DFE50 + QueryPoolPerformanceQueryCreateInfoIntel = 1000210000, // 0x3B9DFE50 + InitializePerformanceApiInfoIntel = 1000210001, // 0x3B9DFE51 + PerformanceMarkerInfoIntel = 1000210002, // 0x3B9DFE52 + PerformanceStreamMarkerInfoIntel = 1000210003, // 0x3B9DFE53 + PerformanceOverrideInfoIntel = 1000210004, // 0x3B9DFE54 + PerformanceConfigurationAcquireInfoIntel = 1000210005, // 0x3B9DFE55 + PhysicalDeviceVulkanMemoryModelFeatures = 1000211000, // 0x3B9E0238 + PhysicalDeviceVulkanMemoryModelFeaturesKhr = 1000211000, // 0x3B9E0238 + PhysicalDevicePciBusInfoPropertiesExt = 1000212000, // 0x3B9E0620 + DisplayNativeHdrSurfaceCapabilitiesAmd = 1000213000, // 0x3B9E0A08 + SwapchainDisplayNativeHdrCreateInfoAmd = 1000213001, // 0x3B9E0A09 + ImagepipeSurfaceCreateInfoFuchsia = 1000214000, // 0x3B9E0DF0 + PhysicalDeviceShaderTerminateInvocationFeaturesKhr = 1000215000, // 0x3B9E11D8 + MetalSurfaceCreateInfoExt = 1000217000, // 0x3B9E19A8 + PhysicalDeviceFragmentDensityMapFeaturesExt = 1000218000, // 0x3B9E1D90 + PhysicalDeviceFragmentDensityMapPropertiesExt = 1000218001, // 0x3B9E1D91 + RenderPassFragmentDensityMapCreateInfoExt = 1000218002, // 0x3B9E1D92 + PhysicalDeviceScalarBlockLayoutFeatures = 1000221000, // 0x3B9E2948 + PhysicalDeviceScalarBlockLayoutFeaturesExt = 1000221000, // 0x3B9E2948 + PhysicalDeviceSubgroupSizeControlPropertiesExt = 1000225000, // 0x3B9E38E8 + PipelineShaderStageRequiredSubgroupSizeCreateInfoExt = 1000225001, // 0x3B9E38E9 + PhysicalDeviceSubgroupSizeControlFeaturesExt = 1000225002, // 0x3B9E38EA + FragmentShadingRateAttachmentInfoKhr = 1000226000, // 0x3B9E3CD0 + PipelineFragmentShadingRateStateCreateInfoKhr = 1000226001, // 0x3B9E3CD1 + PhysicalDeviceFragmentShadingRatePropertiesKhr = 1000226002, // 0x3B9E3CD2 + PhysicalDeviceFragmentShadingRateFeaturesKhr = 1000226003, // 0x3B9E3CD3 + PhysicalDeviceFragmentShadingRateKhr = 1000226004, // 0x3B9E3CD4 + PhysicalDeviceShaderCoreProperties2Amd = 1000227000, // 0x3B9E40B8 + PhysicalDeviceCoherentMemoryFeaturesAmd = 1000229000, // 0x3B9E4888 + PhysicalDeviceShaderImageAtomicInt64FeaturesExt = 1000234000, // 0x3B9E5C10 + PhysicalDeviceMemoryBudgetPropertiesExt = 1000237000, // 0x3B9E67C8 + PhysicalDeviceMemoryPriorityFeaturesExt = 1000238000, // 0x3B9E6BB0 + MemoryPriorityAllocateInfoExt = 1000238001, // 0x3B9E6BB1 + SurfaceProtectedCapabilitiesKhr = 1000239000, // 0x3B9E6F98 + PhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV = 1000240000, // 0x3B9E7380 + PhysicalDeviceSeparateDepthStencilLayoutsFeatures = 1000241000, // 0x3B9E7768 + PhysicalDeviceSeparateDepthStencilLayoutsFeaturesKhr = 1000241000, // 0x3B9E7768 + AttachmentReferenceStencilLayout = 1000241001, // 0x3B9E7769 + AttachmentReferenceStencilLayoutKhr = 1000241001, // 0x3B9E7769 + AttachmentDescriptionStencilLayout = 1000241002, // 0x3B9E776A + AttachmentDescriptionStencilLayoutKhr = 1000241002, // 0x3B9E776A + PhysicalDeviceBufferAddressFeaturesExt = 1000244000, // 0x3B9E8320 + PhysicalDeviceBufferDeviceAddressFeaturesExt = 1000244000, // 0x3B9E8320 + BufferDeviceAddressInfo = 1000244001, // 0x3B9E8321 + BufferDeviceAddressInfoExt = 1000244001, // 0x3B9E8321 + BufferDeviceAddressInfoKhr = 1000244001, // 0x3B9E8321 + BufferDeviceAddressCreateInfoExt = 1000244002, // 0x3B9E8322 + PhysicalDeviceToolPropertiesExt = 1000245000, // 0x3B9E8708 + ImageStencilUsageCreateInfo = 1000246000, // 0x3B9E8AF0 + ImageStencilUsageCreateInfoExt = 1000246000, // 0x3B9E8AF0 + ValidationFeaturesExt = 1000247000, // 0x3B9E8ED8 + PhysicalDevicePresentWaitFeaturesKhr = 1000248000, // 0x3B9E92C0 + PhysicalDeviceCooperativeMatrixFeaturesNV = 1000249000, // 0x3B9E96A8 + CooperativeMatrixPropertiesNV = 1000249001, // 0x3B9E96A9 + PhysicalDeviceCooperativeMatrixPropertiesNV = 1000249002, // 0x3B9E96AA + PhysicalDeviceCoverageReductionModeFeaturesNV = 1000250000, // 0x3B9E9A90 + PipelineCoverageReductionStateCreateInfoNV = 1000250001, // 0x3B9E9A91 + FramebufferMixedSamplesCombinationNV = 1000250002, // 0x3B9E9A92 + PhysicalDeviceFragmentShaderInterlockFeaturesExt = 1000251000, // 0x3B9E9E78 + PhysicalDeviceYcbcrImageArraysFeaturesExt = 1000252000, // 0x3B9EA260 + PhysicalDeviceUniformBufferStandardLayoutFeatures = 1000253000, // 0x3B9EA648 + PhysicalDeviceUniformBufferStandardLayoutFeaturesKhr = 1000253000, // 0x3B9EA648 + PhysicalDeviceProvokingVertexFeaturesExt = 1000254000, // 0x3B9EAA30 + PipelineRasterizationProvokingVertexStateCreateInfoExt = 1000254001, // 0x3B9EAA31 + PhysicalDeviceProvokingVertexPropertiesExt = 1000254002, // 0x3B9EAA32 + SurfaceFullScreenExclusiveInfoExt = 1000255000, // 0x3B9EAE18 + SurfaceFullScreenExclusiveWin32InfoExt = 1000255001, // 0x3B9EAE19 + SurfaceCapabilitiesFullScreenExclusiveExt = 1000255002, // 0x3B9EAE1A + HeadlessSurfaceCreateInfoExt = 1000256000, // 0x3B9EB200 + PhysicalDeviceBufferDeviceAddressFeatures = 1000257000, // 0x3B9EB5E8 + PhysicalDeviceBufferDeviceAddressFeaturesKhr = 1000257000, // 0x3B9EB5E8 + BufferOpaqueCaptureAddressCreateInfo = 1000257002, // 0x3B9EB5EA + BufferOpaqueCaptureAddressCreateInfoKhr = 1000257002, // 0x3B9EB5EA + MemoryOpaqueCaptureAddressAllocateInfo = 1000257003, // 0x3B9EB5EB + MemoryOpaqueCaptureAddressAllocateInfoKhr = 1000257003, // 0x3B9EB5EB + DeviceMemoryOpaqueCaptureAddressInfo = 1000257004, // 0x3B9EB5EC + DeviceMemoryOpaqueCaptureAddressInfoKhr = 1000257004, // 0x3B9EB5EC + PhysicalDeviceLineRasterizationFeaturesExt = 1000259000, // 0x3B9EBDB8 + PipelineRasterizationLineStateCreateInfoExt = 1000259001, // 0x3B9EBDB9 + PhysicalDeviceLineRasterizationPropertiesExt = 1000259002, // 0x3B9EBDBA + PhysicalDeviceShaderAtomicFloatFeaturesExt = 1000260000, // 0x3B9EC1A0 + PhysicalDeviceHostQueryResetFeatures = 1000261000, // 0x3B9EC588 + PhysicalDeviceHostQueryResetFeaturesExt = 1000261000, // 0x3B9EC588 + PhysicalDeviceIndexTypeUint8FeaturesExt = 1000265000, // 0x3B9ED528 + PhysicalDeviceExtendedDynamicStateFeaturesExt = 1000267000, // 0x3B9EDCF8 + PhysicalDevicePipelineExecutablePropertiesFeaturesKhr = 1000269000, // 0x3B9EE4C8 + PipelineInfoKhr = 1000269001, // 0x3B9EE4C9 + PipelineExecutablePropertiesKhr = 1000269002, // 0x3B9EE4CA + PipelineExecutableInfoKhr = 1000269003, // 0x3B9EE4CB + PipelineExecutableStatisticKhr = 1000269004, // 0x3B9EE4CC + PipelineExecutableInternalRepresentationKhr = 1000269005, // 0x3B9EE4CD + PhysicalDeviceShaderAtomicFloat2FeaturesExt = 1000273000, // 0x3B9EF468 + PhysicalDeviceShaderDemoteToHelperInvocationFeaturesExt = 1000276000, // 0x3B9F0020 + PhysicalDeviceDeviceGeneratedCommandsPropertiesNV = 1000277000, // 0x3B9F0408 + GraphicsShaderGroupCreateInfoNV = 1000277001, // 0x3B9F0409 + GraphicsPipelineShaderGroupsCreateInfoNV = 1000277002, // 0x3B9F040A + IndirectCommandsLayoutTokenNV = 1000277003, // 0x3B9F040B + IndirectCommandsLayoutCreateInfoNV = 1000277004, // 0x3B9F040C + GeneratedCommandsInfoNV = 1000277005, // 0x3B9F040D + GeneratedCommandsMemoryRequirementsInfoNV = 1000277006, // 0x3B9F040E + PhysicalDeviceDeviceGeneratedCommandsFeaturesNV = 1000277007, // 0x3B9F040F + PhysicalDeviceInheritedViewportScissorFeaturesNV = 1000278000, // 0x3B9F07F0 + CommandBufferInheritanceViewportScissorInfoNV = 1000278001, // 0x3B9F07F1 + PhysicalDeviceShaderIntegerDotProductFeaturesKhr = 1000280000, // 0x3B9F0FC0 + PhysicalDeviceShaderIntegerDotProductPropertiesKhr = 1000280001, // 0x3B9F0FC1 + PhysicalDeviceTexelBufferAlignmentFeaturesExt = 1000281000, // 0x3B9F13A8 + PhysicalDeviceTexelBufferAlignmentPropertiesExt = 1000281001, // 0x3B9F13A9 + CommandBufferInheritanceRenderPassTransformInfoQCom = 1000282000, // 0x3B9F1790 + RenderPassTransformBeginInfoQCom = 1000282001, // 0x3B9F1791 + PhysicalDeviceDeviceMemoryReportFeaturesExt = 1000284000, // 0x3B9F1F60 + DeviceDeviceMemoryReportCreateInfoExt = 1000284001, // 0x3B9F1F61 + DeviceMemoryReportCallbackDataExt = 1000284002, // 0x3B9F1F62 + PhysicalDeviceRobustness2FeaturesExt = 1000286000, // 0x3B9F2730 + PhysicalDeviceRobustness2PropertiesExt = 1000286001, // 0x3B9F2731 + SamplerCustomBorderColorCreateInfoExt = 1000287000, // 0x3B9F2B18 + PhysicalDeviceCustomBorderColorPropertiesExt = 1000287001, // 0x3B9F2B19 + PhysicalDeviceCustomBorderColorFeaturesExt = 1000287002, // 0x3B9F2B1A + PipelineLibraryCreateInfoKhr = 1000290000, // 0x3B9F36D0 + PresentIDKhr = 1000294000, // 0x3B9F4670 + PhysicalDevicePresentIDFeaturesKhr = 1000294001, // 0x3B9F4671 + PhysicalDevicePrivateDataFeaturesExt = 1000295000, // 0x3B9F4A58 + DevicePrivateDataCreateInfoExt = 1000295001, // 0x3B9F4A59 + PrivateDataSlotCreateInfoExt = 1000295002, // 0x3B9F4A5A + PhysicalDevicePipelineCreationCacheControlFeaturesExt = 1000297000, // 0x3B9F5228 + VideoEncodeInfoKhr = 1000299000, // 0x3B9F59F8 + VideoEncodeRateControlInfoKhr = 1000299001, // 0x3B9F59F9 + PhysicalDeviceDiagnosticsConfigFeaturesNV = 1000300000, // 0x3B9F5DE0 + DeviceDiagnosticsConfigCreateInfoNV = 1000300001, // 0x3B9F5DE1 + ReservedQCom = 1000309000, // 0x3B9F8108 + MemoryBarrier2Khr = 1000314000, // 0x3B9F9490 + BufferMemoryBarrier2Khr = 1000314001, // 0x3B9F9491 + ImageMemoryBarrier2Khr = 1000314002, // 0x3B9F9492 + DependencyInfoKhr = 1000314003, // 0x3B9F9493 + SubmitInfo2Khr = 1000314004, // 0x3B9F9494 + SemaphoreSubmitInfoKhr = 1000314005, // 0x3B9F9495 + CommandBufferSubmitInfoKhr = 1000314006, // 0x3B9F9496 + PhysicalDeviceSynchronization2FeaturesKhr = 1000314007, // 0x3B9F9497 + QueueFamilyCheckpointProperties2NV = 1000314008, // 0x3B9F9498 + CheckpointData2NV = 1000314009, // 0x3B9F9499 + PhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKhr = 1000323000, // 0x3B9FB7B8 + PhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKhr = 1000325000, // 0x3B9FBF88 + PhysicalDeviceFragmentShadingRateEnumsPropertiesNV = 1000326000, // 0x3B9FC370 + PhysicalDeviceFragmentShadingRateEnumsFeaturesNV = 1000326001, // 0x3B9FC371 + PipelineFragmentShadingRateEnumStateCreateInfoNV = 1000326002, // 0x3B9FC372 + AccelerationStructureGeometryMotionTrianglesDataNV = 1000327000, // 0x3B9FC758 + PhysicalDeviceRayTracingMotionBlurFeaturesNV = 1000327001, // 0x3B9FC759 + AccelerationStructureMotionInfoNV = 1000327002, // 0x3B9FC75A + PhysicalDeviceYcbcr2Plane444FormatsFeaturesExt = 1000330000, // 0x3B9FD310 + PhysicalDeviceFragmentDensityMap2FeaturesExt = 1000332000, // 0x3B9FDAE0 + PhysicalDeviceFragmentDensityMap2PropertiesExt = 1000332001, // 0x3B9FDAE1 + CopyCommandTransformInfoQCom = 1000333000, // 0x3B9FDEC8 + PhysicalDeviceImageRobustnessFeaturesExt = 1000335000, // 0x3B9FE698 + PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKhr = 1000336000, // 0x3B9FEA80 + CopyBufferInfo2Khr = 1000337000, // 0x3B9FEE68 + CopyImageInfo2Khr = 1000337001, // 0x3B9FEE69 + CopyBufferToImageInfo2Khr = 1000337002, // 0x3B9FEE6A + CopyImageToBufferInfo2Khr = 1000337003, // 0x3B9FEE6B + BlitImageInfo2Khr = 1000337004, // 0x3B9FEE6C + ResolveImageInfo2Khr = 1000337005, // 0x3B9FEE6D + BufferCopy2Khr = 1000337006, // 0x3B9FEE6E + ImageCopy2Khr = 1000337007, // 0x3B9FEE6F + ImageBlit2Khr = 1000337008, // 0x3B9FEE70 + BufferImageCopy2Khr = 1000337009, // 0x3B9FEE71 + ImageResolve2Khr = 1000337010, // 0x3B9FEE72 + PhysicalDevice4444FormatsFeaturesExt = 1000340000, // 0x3B9FFA20 + DirectfbSurfaceCreateInfoExt = 1000346000, // 0x3BA01190 + PhysicalDeviceRayTracingPipelineFeaturesKhr = 1000347000, // 0x3BA01578 + PhysicalDeviceRayTracingPipelinePropertiesKhr = 1000347001, // 0x3BA01579 + PhysicalDeviceRayQueryFeaturesKhr = 1000348013, // 0x3BA0196D + PhysicalDeviceMutableDescriptorTypeFeaturesValve = 1000351000, // 0x3BA02518 + MutableDescriptorTypeCreateInfoValve = 1000351002, // 0x3BA0251A + PhysicalDeviceVertexInputDynamicStateFeaturesExt = 1000352000, // 0x3BA02900 + VertexInputBindingDescription2Ext = 1000352001, // 0x3BA02901 + VertexInputAttributeDescription2Ext = 1000352002, // 0x3BA02902 + PhysicalDeviceDrmPropertiesExt = 1000353000, // 0x3BA02CE8 + PhysicalDevicePrimitiveTopologyListRestartFeaturesExt = 1000356000, // 0x3BA038A0 + ImportMemoryZirconHandleInfoFuchsia = 1000364000, // 0x3BA057E0 + MemoryZirconHandlePropertiesFuchsia = 1000364001, // 0x3BA057E1 + MemoryGetZirconHandleInfoFuchsia = 1000364002, // 0x3BA057E2 + ImportSemaphoreZirconHandleInfoFuchsia = 1000365000, // 0x3BA05BC8 + SemaphoreGetZirconHandleInfoFuchsia = 1000365001, // 0x3BA05BC9 + BufferCollectionCreateInfoFuchsia = 1000366000, // 0x3BA05FB0 + ImportMemoryBufferCollectionFuchsia = 1000366001, // 0x3BA05FB1 + BufferCollectionImageCreateInfoFuchsia = 1000366002, // 0x3BA05FB2 + BufferCollectionPropertiesFuchsia = 1000366003, // 0x3BA05FB3 + BufferConstraintsInfoFuchsia = 1000366004, // 0x3BA05FB4 + BufferCollectionBufferCreateInfoFuchsia = 1000366005, // 0x3BA05FB5 + ImageConstraintsInfoFuchsia = 1000366006, // 0x3BA05FB6 + ImageFormatConstraintsInfoFuchsia = 1000366007, // 0x3BA05FB7 + SysmemColorSpaceFuchsia = 1000366008, // 0x3BA05FB8 + BufferCollectionConstraintsInfoFuchsia = 1000366009, // 0x3BA05FB9 + SubpassShadingPipelineCreateInfoHuawei = 1000369000, // 0x3BA06B68 + PhysicalDeviceSubpassShadingFeaturesHuawei = 1000369001, // 0x3BA06B69 + PhysicalDeviceSubpassShadingPropertiesHuawei = 1000369002, // 0x3BA06B6A + PhysicalDeviceInvocationMaskFeaturesHuawei = 1000370000, // 0x3BA06F50 + MemoryGetRemoteAddressInfoNV = 1000371000, // 0x3BA07338 + PhysicalDeviceExternalMemoryRdmaFeaturesNV = 1000371001, // 0x3BA07339 + PhysicalDeviceExtendedDynamicState2FeaturesExt = 1000377000, // 0x3BA08AA8 + ScreenSurfaceCreateInfoQnx = 1000378000, // 0x3BA08E90 + PhysicalDeviceColorWriteEnableFeaturesExt = 1000381000, // 0x3BA09A48 + PipelineColorWriteCreateInfoExt = 1000381001, // 0x3BA09A49 + PhysicalDeviceGlobalPriorityQueryFeaturesExt = 1000388000, // 0x3BA0B5A0 + QueueFamilyGlobalPriorityPropertiesExt = 1000388001, // 0x3BA0B5A1 + PhysicalDeviceMultiDrawFeaturesExt = 1000392000, // 0x3BA0C540 + PhysicalDeviceMultiDrawPropertiesExt = 1000392001, // 0x3BA0C541 + PhysicalDevicePageableDeviceLocalMemoryFeaturesExt = 1000412000 // 0x3BA11360 +} \ No newline at end of file From 7863b1d490f4f20551e71dd98bb7e5a7fe54ff90 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Thu, 4 Nov 2021 21:36:23 +0000 Subject: [PATCH 02/34] feat: Now supports limiting allowed structs. * Added tests to check that invalid structs don't compile * Minimal additional code required per struct - just add an interface for each allowed `PNext` struct; and, - add a short static method `Chain` (technically optional), and a short instance method `SetNext`. --- .../PrototypeStructChaining.Test.csproj | 7 +- .../{UnitTestChains.cs => TestChains.cs} | 37 ++++++--- .../TestCompilation.cs | 81 +++++++++++++++++++ PrototypeStructChaining/Bool32.cs | 62 -------------- PrototypeStructChaining/ChainExtensions.cs | 71 ++++++++++++++++ PrototypeStructChaining/DeviceCreateInfo.cs | 51 ++++++++++++ PrototypeStructChaining/IChainable.cs | 15 ++-- ...lDeviceAccelerationStructureFeaturesKHR.cs | 32 +++----- ...hysicalDeviceDescriptorIndexingFeatures.cs | 32 +++----- .../PhysicalDeviceFeatures.cs | 4 +- .../PhysicalDeviceFeatures2.cs | 22 ++--- 11 files changed, 275 insertions(+), 139 deletions(-) rename PrototypeStructChaining.Test/{UnitTestChains.cs => TestChains.cs} (56%) create mode 100644 PrototypeStructChaining.Test/TestCompilation.cs delete mode 100644 PrototypeStructChaining/Bool32.cs create mode 100644 PrototypeStructChaining/ChainExtensions.cs create mode 100644 PrototypeStructChaining/DeviceCreateInfo.cs diff --git a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj index f3281ada30..50c8497523 100644 --- a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj +++ b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj @@ -10,8 +10,9 @@ - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -23,7 +24,7 @@ - + diff --git a/PrototypeStructChaining.Test/UnitTestChains.cs b/PrototypeStructChaining.Test/TestChains.cs similarity index 56% rename from PrototypeStructChaining.Test/UnitTestChains.cs rename to PrototypeStructChaining.Test/TestChains.cs index 0ed4f5ca5a..19d47caa19 100644 --- a/PrototypeStructChaining.Test/UnitTestChains.cs +++ b/PrototypeStructChaining.Test/TestChains.cs @@ -3,21 +3,25 @@ namespace PrototypeStructChaining.Test; -public class UnitTestChains +public class TestChains { [Fact] public unsafe void TestCreateNext() { PhysicalDeviceFeatures2 + // The Chain method, is a convenient static, to provide a consistent syntax. .Chain(out var features2) - .CreateNext(out var indexingFeatures) - .CreateNext(out var accelerationStructureFeaturesKhr) - .End(); + // CreateNext will create an empty struct, with the correct SType (as well as ensuring the + // caller SType is coerced correctly. + .CreateNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + .CreateNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + // Ensure all pointers set correctly Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); Assert.Equal((nint) (&accelerationStructureFeaturesKhr), (nint) indexingFeatures.PNext); Assert.Equal((nint) 0, (nint) accelerationStructureFeaturesKhr.PNext); + // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, @@ -35,12 +39,12 @@ public unsafe void TestSetNext() { AccelerationStructure = true }; - + PhysicalDeviceFeatures2 .Chain(out var features2) - .SetNext(ref indexingFeatures) - .SetNext(ref accelerationStructureFeaturesKhr) - .End(); + // SetNext accepts an existing struct, note, it will coerce the SType and blank the PNext + .SetNext(ref indexingFeatures) + .SetNext(ref accelerationStructureFeaturesKhr); Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); Assert.Equal((nint) (&accelerationStructureFeaturesKhr), (nint) indexingFeatures.PNext); @@ -50,8 +54,23 @@ public unsafe void TestSetNext() Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeaturesKhr.SType); - + Assert.True(indexingFeatures.ShaderInputAttachmentArrayDynamicIndexing); Assert.True(accelerationStructureFeaturesKhr.AccelerationStructure); } + + [Fact] + public unsafe void TestWithoutChain() + { + // We don't have to use the Chain() pattern, as we can pass start with an existing struct + var createInfo = new DeviceCreateInfo(); + // However, note that CreateNext will still coerce the SType of createInfo. + createInfo.CreateNext(out PhysicalDeviceFeatures2 features2); + Assert.Equal((nint) (&features2), (nint) createInfo.PNext); + Assert.Equal((nint) 0, (nint) features2.PNext); + + // Note, even though we didn't use chain, we have still coerced the SType + Assert.Equal(StructureType.DeviceCreateInfo, createInfo.SType); + Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); + } } \ No newline at end of file diff --git a/PrototypeStructChaining.Test/TestCompilation.cs b/PrototypeStructChaining.Test/TestCompilation.cs new file mode 100644 index 0000000000..3087b90824 --- /dev/null +++ b/PrototypeStructChaining.Test/TestCompilation.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Silk.Net.Vulkan; +using Xunit; + +namespace PrototypeStructChaining.Test; + +public class TestCompilation +{ + private static readonly Lazy> References = new(() => + ((string?) AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") ?? string.Empty) + .Split(Path.PathSeparator) + .Select(r => MetadataReference.CreateFromFile(r)) + .Concat(new[] {MetadataReference.CreateFromFile(typeof(StructureType).Assembly.Location)}) + .ToArray() + ); + + private static readonly string CodeTemplate = @" +using System; +using Silk.Net.Vulkan; + +public class Test +{{ + public void DoTest() + {{ + {0} + }} +}}"; + + private IReadOnlyList CheckCompile(string code) + { + var assemblyName = Path.GetRandomFileName(); + var compilation = CSharpCompilation.Create( + assemblyName, + new[] {CSharpSyntaxTree.ParseText(string.Format(CodeTemplate, code))}, + References.Value, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + using var ms = new MemoryStream(); + var result = compilation.Emit(ms); + + if (result.Success) + return Array.Empty(); + + return result.Diagnostics.Where(diagnostic => + diagnostic.IsWarningAsError || + diagnostic.Severity == DiagnosticSeverity.Error) + .ToArray(); + } + + [Fact] + public unsafe void TestCantAddUnsupportedNext() + { + var diagnostics = CheckCompile( + @"PhysicalDeviceFeatures2 + .Chain(out var features2) + .CreateNext(out DeviceCreateInfo createInfo);"); + + Assert.Single(diagnostics); + var error = diagnostics.First(); + // error CS0315: The type 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' cannot be used as type parameter 'TChain' in the generic type or method 'ChainExtensions.CreateNext(ref TChain, out TNext)'. There is no boxing conversion from 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' to 'Silk.Net.Vulkan.IChainable'. + Assert.Equal("CS0315", error.Id); + } + + [Fact] + public unsafe void TestCanAddSupportedNext() + { + var diagnostics = CheckCompile( + @"DeviceCreateInfo + .Chain(out var createInfo) + .CreateNext(out PhysicalDeviceFeatures2 features2);"); + + Assert.Empty(diagnostics); + } +} \ No newline at end of file diff --git a/PrototypeStructChaining/Bool32.cs b/PrototypeStructChaining/Bool32.cs deleted file mode 100644 index 8d86edd14b..0000000000 --- a/PrototypeStructChaining/Bool32.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace Silk.Net.Vulkan; - -/// A 32-bit boolean. -public readonly struct Bool32 -{ - /// Gets the 32-bit value for this boolean. - public uint Value { get; } - - /// - /// Creates a 32-bit boolean from the given 32-bit unsigned integer. - /// - /// The 32-bit unsigned integer value. - public Bool32(uint val) - { - Value = val; - } - - /// - /// Creates a 32-bit boolean from the given managed boolean. - /// - /// The boolean value. - public Bool32(bool val) - { - Value = val ? 1U : 0U; - } - - /// Converts this 32-bit boolean to a managed boolean. - /// The 32-bit boolean. - /// The managed boolean. - public static implicit operator bool(Bool32 val) - { - return val.Value == 1U; - } - - /// - /// Converts this 32-bit boolean to a 32-bit unsigned integer. - /// - /// The 32-bit boolean. - /// The 32-bit unsigned integer. - public static implicit operator uint(Bool32 val) - { - return val.Value; - } - - /// - /// Creates a 32-bit boolean from the given managed boolean. - /// - /// The boolean value. - public static implicit operator Bool32(bool val) - { - return new Bool32(val); - } - - /// - /// Creates a 32-bit boolean from the given 32-bit unsigned integer. - /// - /// The 32-bit unsigned integer value. - public static implicit operator Bool32(uint val) - { - return new Bool32(val); - } -} \ No newline at end of file diff --git a/PrototypeStructChaining/ChainExtensions.cs b/PrototypeStructChaining/ChainExtensions.cs new file mode 100644 index 0000000000..9957409569 --- /dev/null +++ b/PrototypeStructChaining/ChainExtensions.cs @@ -0,0 +1,71 @@ +namespace Silk.Net.Vulkan; + +public static class ChainExtensions +{ + /// + /// Sets the next structure in a chain. + /// + /// The current chain + /// The next value in the chain + /// The type of the current chain + /// The type of the next value + /// A reference to the next value in the chain + /// + /// WARNING: The supplied value will have it's own next ptr nulled. + /// Note that both the supplied chain, and the next value will have their `SType` correctly set. + /// To use + /// + /// var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + /// { + /// ShaderInputAttachmentArrayDynamicIndexing = true + /// }; + /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKHR + /// { + /// AccelerationStructure = true + /// }; + /// + /// PhysicalDeviceFeatures2 + /// .Chain(out var features2) + /// .SetNext(ref indexingFeatures) + /// .SetNext(ref accelerationStructureFeaturesKhr); + /// + /// + public static unsafe ref TNext SetNext(this ref TChain chain, ref TNext capture) + where TChain : struct, IChainable + where TNext : struct, IChainable + { + capture.SetNext(); + var reference = __makeref(capture); + chain.SetNext((void*) *(IntPtr*) &reference); + return ref capture; + } + + /// + /// Creates the next structure in a chain. + /// + /// The current chain + /// The next value created in the chain + /// The type of the current chain + /// The type of the next value + /// A reference to the newly created next value in the chain + /// + /// Note that both the supplied chain, and the newly created next value will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .Chain(out var features2) + /// .CreateNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + /// .CreateNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + /// + /// + public static unsafe ref TNext CreateNext(this ref TChain chain, out TNext capture) + where TChain : struct, IChainable + where TNext : struct, IChainable + { + capture = default; + capture.SetNext(); + var reference = __makeref(capture); + chain.SetNext((void*) *(IntPtr*) &reference); + return ref capture; + } +} \ No newline at end of file diff --git a/PrototypeStructChaining/DeviceCreateInfo.cs b/PrototypeStructChaining/DeviceCreateInfo.cs new file mode 100644 index 0000000000..a38c141c22 --- /dev/null +++ b/PrototypeStructChaining/DeviceCreateInfo.cs @@ -0,0 +1,51 @@ +namespace Silk.Net.Vulkan; + +public struct DeviceCreateInfo : + IChainable, + IChainable, + IChainable +{ + /// + public StructureType SType; + + /// + public unsafe void* PNext; + + /// + public uint Flags; + + // NOTE Truncated for example + + + public unsafe DeviceCreateInfo( + StructureType? sType = StructureType.DeviceCreateInfo, + void* pNext = null, + uint? flags = null) + : this() + { + if (sType.HasValue) + SType = sType.Value; + if ((IntPtr) pNext != IntPtr.Zero) + PNext = pNext; + if (flags.HasValue) + Flags = flags.Value; + // NOTE Truncated for example + } + + + #region Chaining Support + + public static unsafe ref DeviceCreateInfo Chain(out DeviceCreateInfo capture) + { + capture = new DeviceCreateInfo(StructureType.DeviceCreateInfo); + return ref capture; + } + + public unsafe void SetNext(void* next = default) + { + SType = StructureType.DeviceCreateInfo; + PNext = next; + } + + #endregion +} \ No newline at end of file diff --git a/PrototypeStructChaining/IChainable.cs b/PrototypeStructChaining/IChainable.cs index 3a3d44100b..72d6093f9a 100644 --- a/PrototypeStructChaining/IChainable.cs +++ b/PrototypeStructChaining/IChainable.cs @@ -1,13 +1,18 @@ namespace Silk.Net.Vulkan; +/// +/// Base interface for any struct that has can set the next value. +/// public interface IChainable { + unsafe void SetNext(void* next = default); } -public interface IExtendsDeviceCreateInfoChain : IChainable -{ -} - -public interface IExtendsPhysicalDeviceFeatures2Chain : IChainable +/// +/// Generic interface indicating which structs can be set in the `PNext` value. +/// +/// A valid next structure +public interface IChainable : IChainable + where TNext : IChainable { } \ No newline at end of file diff --git a/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs b/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs index 74876ce5f7..05ec4692d4 100644 --- a/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs +++ b/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs @@ -1,7 +1,7 @@ namespace Silk.Net.Vulkan; -public struct PhysicalDeviceAccelerationStructureFeaturesKHR : IExtendsDeviceCreateInfoChain, - IExtendsPhysicalDeviceFeatures2Chain +public struct PhysicalDeviceAccelerationStructureFeaturesKHR : + IChainable { /// public StructureType SType; @@ -10,14 +10,14 @@ public struct PhysicalDeviceAccelerationStructureFeaturesKHR : IExtendsDeviceCre public unsafe void* PNext; /// - public Bool32 AccelerationStructure; + public bool AccelerationStructure; // NOTE Truncated for example public unsafe PhysicalDeviceAccelerationStructureFeaturesKHR( StructureType? sType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, void* pNext = null, - Bool32? accelerationStructure = null) + bool? accelerationStructure = null) : this() { if (sType.HasValue) @@ -29,31 +29,21 @@ public unsafe PhysicalDeviceAccelerationStructureFeaturesKHR( // NOTE Truncated for example } - - #region Chaining Support - public static unsafe ref PhysicalDeviceAccelerationStructureFeaturesKHR Chain(out PhysicalDeviceAccelerationStructureFeaturesKHR capture) - { - capture = new PhysicalDeviceAccelerationStructureFeaturesKHR(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr); - return ref capture; - } - public void End() => SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; + #region Chaining Support - public unsafe ref T SetNext(ref T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + public static unsafe ref PhysicalDeviceAccelerationStructureFeaturesKHR Chain( + out PhysicalDeviceAccelerationStructureFeaturesKHR capture) { - SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; - var reference = __makeref(capture); - PNext = (void*) *(IntPtr*) &reference; + capture = new PhysicalDeviceAccelerationStructureFeaturesKHR(StructureType + .PhysicalDeviceAccelerationStructureFeaturesKhr); return ref capture; } - public unsafe ref T CreateNext(out T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + public unsafe void SetNext(void* next = default) { SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; - capture = default; - var reference = __makeref(capture); - PNext = (void*) *(IntPtr*) &reference; - return ref capture; + PNext = next; } #endregion diff --git a/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs b/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs index 8d5f5d9238..ebeeadf515 100644 --- a/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs +++ b/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs @@ -1,7 +1,7 @@ namespace Silk.Net.Vulkan; -public struct PhysicalDeviceDescriptorIndexingFeatures : IExtendsDeviceCreateInfoChain, - IExtendsPhysicalDeviceFeatures2Chain +public struct PhysicalDeviceDescriptorIndexingFeatures : + IChainable { /// public StructureType SType; @@ -10,14 +10,14 @@ public struct PhysicalDeviceDescriptorIndexingFeatures : IExtendsDeviceCreateInf public unsafe void* PNext; /// - public Bool32 ShaderInputAttachmentArrayDynamicIndexing; + public bool ShaderInputAttachmentArrayDynamicIndexing; // NOTE Truncated for example public unsafe PhysicalDeviceDescriptorIndexingFeatures( StructureType? sType = StructureType.PhysicalDeviceDescriptorIndexingFeaturesExt, void* pNext = null, - Bool32? shaderInputAttachmentArrayDynamicIndexing = null) + bool? shaderInputAttachmentArrayDynamicIndexing = null) : this() { if (sType.HasValue) @@ -31,29 +31,19 @@ public unsafe PhysicalDeviceDescriptorIndexingFeatures( } #region Chaining Support - public static unsafe ref PhysicalDeviceDescriptorIndexingFeatures Chain(out PhysicalDeviceDescriptorIndexingFeatures capture) - { - capture = new PhysicalDeviceDescriptorIndexingFeatures(StructureType.PhysicalDeviceDescriptorIndexingFeatures); - return ref capture; - } - public void End() => SType = StructureType.PhysicalDeviceDescriptorIndexingFeatures; - - public unsafe ref T SetNext(ref T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + public static unsafe ref PhysicalDeviceDescriptorIndexingFeatures Chain( + out PhysicalDeviceDescriptorIndexingFeatures capture) { - SType = StructureType.PhysicalDeviceDescriptorIndexingFeatures; - var reference = __makeref(capture); - PNext = (void*) *(IntPtr*) &reference; + capture = new PhysicalDeviceDescriptorIndexingFeatures( + StructureType.PhysicalDeviceDescriptorIndexingFeaturesExt); return ref capture; } - public unsafe ref T CreateNext(out T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + public unsafe void SetNext(void* next = default) { - SType = StructureType.PhysicalDeviceDescriptorIndexingFeatures; - capture = default; - var reference = __makeref(capture); - PNext = (void*) *(IntPtr*) &reference; - return ref capture; + SType = StructureType.PhysicalDeviceDescriptorIndexingFeaturesExt; + PNext = next; } #endregion diff --git a/PrototypeStructChaining/PhysicalDeviceFeatures.cs b/PrototypeStructChaining/PhysicalDeviceFeatures.cs index f20a4d8c8c..d38a0d2e30 100644 --- a/PrototypeStructChaining/PhysicalDeviceFeatures.cs +++ b/PrototypeStructChaining/PhysicalDeviceFeatures.cs @@ -3,12 +3,12 @@ public struct PhysicalDeviceFeatures { /// - public Bool32 RobustBufferAccess; + public bool RobustBufferAccess; // NOTE Truncated for example public PhysicalDeviceFeatures( - Bool32? robustBufferAccess = null) + bool? robustBufferAccess = null) : this() { if (robustBufferAccess.HasValue) diff --git a/PrototypeStructChaining/PhysicalDeviceFeatures2.cs b/PrototypeStructChaining/PhysicalDeviceFeatures2.cs index 069b5c0faf..8857e32c4e 100644 --- a/PrototypeStructChaining/PhysicalDeviceFeatures2.cs +++ b/PrototypeStructChaining/PhysicalDeviceFeatures2.cs @@ -2,7 +2,9 @@ namespace Silk.Net.Vulkan; -public struct PhysicalDeviceFeatures2 : IExtendsDeviceCreateInfoChain +public struct PhysicalDeviceFeatures2 : + IChainable, + IChainable { public StructureType SType; public unsafe void* PNext; @@ -24,29 +26,17 @@ public unsafe PhysicalDeviceFeatures2( } #region Chaining Support + public static unsafe ref PhysicalDeviceFeatures2 Chain(out PhysicalDeviceFeatures2 capture) { capture = new PhysicalDeviceFeatures2(StructureType.PhysicalDeviceFeatures2); return ref capture; } - public void End() => SType = StructureType.PhysicalDeviceFeatures2; - - public unsafe ref T SetNext(ref T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain - { - SType = StructureType.PhysicalDeviceFeatures2; - var reference = __makeref(capture); - PNext = (void*) *(IntPtr*) &reference; - return ref capture; - } - - public unsafe ref T CreateNext(out T capture) where T : struct, IExtendsPhysicalDeviceFeatures2Chain + public unsafe void SetNext(void* next = default) { SType = StructureType.PhysicalDeviceFeatures2; - capture = default; - var reference = __makeref(capture); - PNext = (void*) *(IntPtr*) &reference; - return ref capture; + PNext = next; } #endregion From babe08f5bbd3a4d9119dae502f77bea988fe1622 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Thu, 4 Nov 2021 21:57:26 +0000 Subject: [PATCH 03/34] docs: Added Readme.md --- PrototypeStructChaining.Test/TestChains.cs | 9 ++- Readme.md | 90 ++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 Readme.md diff --git a/PrototypeStructChaining.Test/TestChains.cs b/PrototypeStructChaining.Test/TestChains.cs index 19d47caa19..2da49c64ea 100644 --- a/PrototypeStructChaining.Test/TestChains.cs +++ b/PrototypeStructChaining.Test/TestChains.cs @@ -62,8 +62,11 @@ public unsafe void TestSetNext() [Fact] public unsafe void TestWithoutChain() { - // We don't have to use the Chain() pattern, as we can pass start with an existing struct - var createInfo = new DeviceCreateInfo(); + // We don't have to use the Chain() pattern, as we can start with an existing struct + var createInfo = new DeviceCreateInfo + { + Flags = 1U + }; // However, note that CreateNext will still coerce the SType of createInfo. createInfo.CreateNext(out PhysicalDeviceFeatures2 features2); Assert.Equal((nint) (&features2), (nint) createInfo.PNext); @@ -72,5 +75,7 @@ public unsafe void TestWithoutChain() // Note, even though we didn't use chain, we have still coerced the SType Assert.Equal(StructureType.DeviceCreateInfo, createInfo.SType); Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); + + Assert.Equal(1U, createInfo.Flags); } } \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000000..45f379db20 --- /dev/null +++ b/Readme.md @@ -0,0 +1,90 @@ +# Prototype Struct Chaining + +This repository implements a prototype solution for Struct Chaining in [Silk.Net](https://github.com/dotnet/Silk.NET) + +## Design Goals + +* **Backward compatibility** - the chaining system should not change the existing structs, but add functionality. +* **Minimal bloat** - the minimum amount of new generated code was sought. +* **Discoverability** - it should be as easy as possible for a new user to discover +* **Compile-time Validation** - it should prevent chaining invalid structures (as much as possible) during compilation +* **Type coercion** - it should set the SType of chained structures. +* **Compact usage** - it should reduce copy-pasta code. +* **Avoid the heap** - boxing should be avoided +* **Well Tested** - tests were added to ensure pointers are correctly set, and compilation failures occur. + +All of these goals were met. + +## Usage + +The proposal provides for the following usage patterns: + +### CreateNext + +The most common use case is to create an empty structure to be populated by the Vulkan API, this can now be done like so: + +```csharp +PhysicalDeviceFeatures2 + // The Chain method, is a convenient static, to provide a consistent syntax. + .Chain(out var features2) + // CreateNext will create an empty struct, with the correct SType (as well as ensuring the + // caller SType is coerced correctly. + .CreateNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + .CreateNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); +``` + +We start by using the static `Chain` method, this is a convenience method that is not required, but it provides a more readable style. + +Each method `out`puts a struct into the local stackframe for querying once populated. Despite generics and interface being used, boxing doesn't not occur. + +### SetNext + +Sometimes we may wish to set the initial state of a structure, we can do this with `SetNext`: + +```csharp +var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures +{ + ShaderInputAttachmentArrayDynamicIndexing = true +}; +var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKHR +{ + AccelerationStructure = true +}; + +PhysicalDeviceFeatures2 + .Chain(out var features2) + // SetNext accepts an existing struct, note, it will coerce the SType and blank the PNext + .SetNext(ref indexingFeatures) + .SetNext(ref accelerationStructureFeaturesKhr); +``` + +*NOTE* you can mix and match `CreateNext` and `SetNext` in the same chain. + +### Without Chain + +The use of the `Chain` method is entirely optional, for example if we wish to + +```csharp +// We don't have to use the Chain() pattern, as we can start with an existing struct +var createInfo = new DeviceCreateInfo +{ + Flags = 1U +}; +// However, note that CreateNext will still coerce the SType of createInfo. +createInfo.CreateNext(out PhysicalDeviceFeatures2 features2); +``` + +## Changes required + +* Add the `IChainable` and `IChainable` interfaces. +* Add the `ChainExtensions` extension methods `SetNext` and `CreateNext`. +* Add the small instance `void SetNext(void*)` method to each structure (this is required). +* Add the small static `Chain` method to each structure (note, this is optional sugar, allowing for 'single statement' building). +* Add `IChainable` interfaces to every chainable struct to indicate each valid structure accepted by `PNext`, eg.: +```csharp +public struct DeviceCreateInfo : + IChainable, + IChainable, + IChainable ... +``` + From 58865bfb14be8436dd2315a9db9a91866e263773 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Thu, 4 Nov 2021 22:04:26 +0000 Subject: [PATCH 04/34] fix: Change __makeref to Unsafe.AsPointer --- PrototypeStructChaining/ChainExtensions.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PrototypeStructChaining/ChainExtensions.cs b/PrototypeStructChaining/ChainExtensions.cs index 9957409569..2621933697 100644 --- a/PrototypeStructChaining/ChainExtensions.cs +++ b/PrototypeStructChaining/ChainExtensions.cs @@ -1,3 +1,5 @@ +using System.Runtime.CompilerServices; + namespace Silk.Net.Vulkan; public static class ChainExtensions @@ -35,7 +37,7 @@ public static unsafe ref TNext SetNext(this ref TChain chain, ref where TNext : struct, IChainable { capture.SetNext(); - var reference = __makeref(capture); + var reference = Unsafe.AsPointer(ref capture); chain.SetNext((void*) *(IntPtr*) &reference); return ref capture; } @@ -64,7 +66,7 @@ public static unsafe ref TNext CreateNext(this ref TChain chain, { capture = default; capture.SetNext(); - var reference = __makeref(capture); + var reference = Unsafe.AsPointer(ref capture); chain.SetNext((void*) *(IntPtr*) &reference); return ref capture; } From 73763e6bc6579ce33bb5d6367709aece7382c3eb Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Fri, 5 Nov 2021 09:31:17 +0000 Subject: [PATCH 05/34] chore: Retargeting Retargeted project to ensure that it only targets the same includes, etc. as `Silk.Next.Core` and `Silk.Net.Vulkan` --- .idea/.idea.PrototypeStructChaining/.idea/vcs.xml | 7 +++++++ .../PrototypeStructChaining.Test.csproj | 12 ++++++++---- PrototypeStructChaining/IChainable.cs | 2 +- .../PrototypeStructChaining.csproj | 14 +++++++++++++- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/.idea/.idea.PrototypeStructChaining/.idea/vcs.xml b/.idea/.idea.PrototypeStructChaining/.idea/vcs.xml index 94a25f7f4c..029a1a823f 100644 --- a/.idea/.idea.PrototypeStructChaining/.idea/vcs.xml +++ b/.idea/.idea.PrototypeStructChaining/.idea/vcs.xml @@ -1,5 +1,12 @@ + + + + + + + diff --git a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj index 50c8497523..16f0649673 100644 --- a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj +++ b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj @@ -10,9 +10,9 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -24,7 +24,11 @@ - + + + + + diff --git a/PrototypeStructChaining/IChainable.cs b/PrototypeStructChaining/IChainable.cs index 72d6093f9a..1528c142bd 100644 --- a/PrototypeStructChaining/IChainable.cs +++ b/PrototypeStructChaining/IChainable.cs @@ -12,7 +12,7 @@ public interface IChainable /// Generic interface indicating which structs can be set in the `PNext` value. /// /// A valid next structure -public interface IChainable : IChainable +public interface IChainable : IChainable where TNext : IChainable { } \ No newline at end of file diff --git a/PrototypeStructChaining/PrototypeStructChaining.csproj b/PrototypeStructChaining/PrototypeStructChaining.csproj index 211c366972..9ba92105d5 100644 --- a/PrototypeStructChaining/PrototypeStructChaining.csproj +++ b/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -1,11 +1,23 @@ - net6.0 + netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0 + 10 enable enable true Silk.Net.Vulkan + + + + + + + + + + + From 81cc29c8e6955074b63cceafe0c7c1f1bf72ff8e Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Fri, 5 Nov 2021 13:28:58 +0000 Subject: [PATCH 06/34] refactor: Various changes * Added `IStructureType` for any struct that has a `StructureType SType` field. This is usually added automatically by one of the other interfaces; and allows the structure type to be automatically corrected and retrieved using the `StructureType IStructuredType.StructureType()` method. * Added `IChainStart` to indicate a type that can form the start of a chain. * `IChainable<...>` was replaced with `IExtendsChain` which matches the Vulkan specification more readily. * The chaining methods now all accept, and return, a reference to an `IChainStart`, making it easier to scan a chain for existing items, and making use of the auto-generated `IExtendsChain` to validate types at compile time. * `SetNext`, by default, will now replace existing chain entries if they match the supplied `SType`. This behaviour can be overriden with the optional `alwaysAdd` parameter. * `CreateNext` is now called `AddNext` to indicate it always adds to the end of a Chain.cs * `TryAddNext` added to only create a new structure if it is not already there. * `IndexOf` added to return the index of a structure in a chain. * Updated Readme.md. --- .../PrototypeStructChaining.Test.csproj | 10 +- PrototypeStructChaining.Test/TestChains.cs | 112 +++++++++++- .../TestCompilation.cs | 6 +- PrototypeStructChaining/Chain.cs | 17 ++ PrototypeStructChaining/ChainExtensions.cs | 171 +++++++++++++++--- PrototypeStructChaining/DeviceCreateInfo.cs | 23 ++- PrototypeStructChaining/IChainStart.cs | 10 + PrototypeStructChaining/IChainable.cs | 15 +- PrototypeStructChaining/IExtendsChain.cs | 10 + PrototypeStructChaining/IStructuredType.cs | 12 ++ ...lDeviceAccelerationStructureFeaturesKHR.cs | 17 +- ...hysicalDeviceDescriptorIndexingFeatures.cs | 17 +- .../PhysicalDeviceFeatures2.cs | 27 +-- .../PrototypeStructChaining.csproj | 14 +- Readme.md | 110 +++++++++-- 15 files changed, 444 insertions(+), 127 deletions(-) create mode 100644 PrototypeStructChaining/Chain.cs create mode 100644 PrototypeStructChaining/IChainStart.cs create mode 100644 PrototypeStructChaining/IExtendsChain.cs create mode 100644 PrototypeStructChaining/IStructuredType.cs diff --git a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj index 16f0649673..9353923378 100644 --- a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj +++ b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj @@ -10,9 +10,9 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -24,11 +24,11 @@ - + - + diff --git a/PrototypeStructChaining.Test/TestChains.cs b/PrototypeStructChaining.Test/TestChains.cs index 2da49c64ea..5d5080c6ff 100644 --- a/PrototypeStructChaining.Test/TestChains.cs +++ b/PrototypeStructChaining.Test/TestChains.cs @@ -6,15 +6,15 @@ namespace PrototypeStructChaining.Test; public class TestChains { [Fact] - public unsafe void TestCreateNext() + public unsafe void TestAddNext() { PhysicalDeviceFeatures2 // The Chain method, is a convenient static, to provide a consistent syntax. .Chain(out var features2) - // CreateNext will create an empty struct, with the correct SType (as well as ensuring the - // caller SType is coerced correctly. - .CreateNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) - .CreateNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + // AddNext will create an empty struct, with the correct SType (as well as ensuring the + // chain's SType is coerced correctly. + .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); // Ensure all pointers set correctly Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); @@ -26,6 +26,31 @@ public unsafe void TestCreateNext() Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeaturesKhr.SType); + + // Check indices + Assert.Equal(1, features2.IndexOf(ref indexingFeatures)); + Assert.Equal(2, features2.IndexOf(ref accelerationStructureFeaturesKhr)); + } + + [Fact] + public unsafe void TestTryAddNext() + { + PhysicalDeviceFeatures2 + // The Chain method, is a convenient static, to provide a consistent syntax. + .Chain(out var features2) + // AddNext will create an empty struct, with the correct SType (as well as ensuring the + // chain's SType is coerced correctly. + .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures); + + // Ensure all pointers set correctly + Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); + + features2.TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures2, out var added); + Assert.False(added); } [Fact] @@ -59,6 +84,77 @@ public unsafe void TestSetNext() Assert.True(accelerationStructureFeaturesKhr.AccelerationStructure); } + [Fact] + public unsafe void TestSetNextUpdates() + { + var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + { + ShaderInputAttachmentArrayDynamicIndexing = true + }; + + PhysicalDeviceFeatures2 + .Chain(out var features2) + // SetNext accepts an existing struct, note, it will coerce the SType and blank the PNext + .SetNext(ref indexingFeatures); + + Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); + Assert.Equal((nint) 0, (nint) indexingFeatures.PNext); + + Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); + + // Update indexing features + var indexingFeatures2 = new PhysicalDeviceDescriptorIndexingFeatures + { + ShaderInputAttachmentArrayDynamicIndexing = false + }; + features2.SetNext(ref indexingFeatures2); + + Assert.Equal((nint) (&indexingFeatures2), (nint) features2.PNext); + Assert.Equal((nint) 0, (nint) indexingFeatures2.PNext); + + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures2.SType); + + Assert.Equal(1, features2.IndexOf(ref indexingFeatures2)); + Assert.True(features2.IndexOf(ref indexingFeatures) < 0); + } + + [Fact] + public unsafe void TestSetNextAlwaysAdd() + { + var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + { + ShaderInputAttachmentArrayDynamicIndexing = true + }; + + PhysicalDeviceFeatures2 + .Chain(out var features2) + // SetNext accepts an existing struct, note, it will coerce the SType and blank the PNext + .SetNext(ref indexingFeatures); + + Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); + Assert.Equal((nint) 0, (nint) indexingFeatures.PNext); + + Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); + + // Update indexing features + var indexingFeatures2 = new PhysicalDeviceDescriptorIndexingFeatures + { + ShaderInputAttachmentArrayDynamicIndexing = false + }; + features2.SetNext(ref indexingFeatures2, true); + + Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); + Assert.Equal((nint) (&indexingFeatures2), (nint) indexingFeatures.PNext); + Assert.Equal((nint) 0, (nint) indexingFeatures2.PNext); + + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures2.SType); + + Assert.Equal(1, features2.IndexOf(ref indexingFeatures)); + Assert.Equal(2, features2.IndexOf(ref indexingFeatures2)); + } + [Fact] public unsafe void TestWithoutChain() { @@ -67,15 +163,15 @@ public unsafe void TestWithoutChain() { Flags = 1U }; - // However, note that CreateNext will still coerce the SType of createInfo. - createInfo.CreateNext(out PhysicalDeviceFeatures2 features2); + // However, note that AddNext will still coerce the SType of createInfo. + createInfo.AddNext(out PhysicalDeviceFeatures2 features2); Assert.Equal((nint) (&features2), (nint) createInfo.PNext); Assert.Equal((nint) 0, (nint) features2.PNext); // Note, even though we didn't use chain, we have still coerced the SType Assert.Equal(StructureType.DeviceCreateInfo, createInfo.SType); Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); - + Assert.Equal(1U, createInfo.Flags); } } \ No newline at end of file diff --git a/PrototypeStructChaining.Test/TestCompilation.cs b/PrototypeStructChaining.Test/TestCompilation.cs index 3087b90824..21ab41240c 100644 --- a/PrototypeStructChaining.Test/TestCompilation.cs +++ b/PrototypeStructChaining.Test/TestCompilation.cs @@ -60,11 +60,11 @@ public unsafe void TestCantAddUnsupportedNext() var diagnostics = CheckCompile( @"PhysicalDeviceFeatures2 .Chain(out var features2) - .CreateNext(out DeviceCreateInfo createInfo);"); + .AddNext(out DeviceCreateInfo createInfo);"); Assert.Single(diagnostics); var error = diagnostics.First(); - // error CS0315: The type 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' cannot be used as type parameter 'TChain' in the generic type or method 'ChainExtensions.CreateNext(ref TChain, out TNext)'. There is no boxing conversion from 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' to 'Silk.Net.Vulkan.IChainable'. + // error CS0315: The type 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' cannot be used as type parameter 'TChain' in the generic type or method 'ChainExtensions.AddNext(ref TChain, out TNext)'. There is no boxing conversion from 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' to 'Silk.Net.Vulkan.IChainable'. Assert.Equal("CS0315", error.Id); } @@ -74,7 +74,7 @@ public unsafe void TestCanAddSupportedNext() var diagnostics = CheckCompile( @"DeviceCreateInfo .Chain(out var createInfo) - .CreateNext(out PhysicalDeviceFeatures2 features2);"); + .AddNext(out PhysicalDeviceFeatures2 features2);"); Assert.Empty(diagnostics); } diff --git a/PrototypeStructChaining/Chain.cs b/PrototypeStructChaining/Chain.cs new file mode 100644 index 0000000000..5f0ff03b0f --- /dev/null +++ b/PrototypeStructChaining/Chain.cs @@ -0,0 +1,17 @@ +namespace Silk.Net.Vulkan; + +/// +/// Header struct of all chainable structs. +/// +public struct Chain : IChainable +{ + public StructureType SType; + public unsafe Chain* PNext; + + /// + /// Note, this doesn't coerce the type. + StructureType IStructuredType.StructureType() + { + return SType; + } +} \ No newline at end of file diff --git a/PrototypeStructChaining/ChainExtensions.cs b/PrototypeStructChaining/ChainExtensions.cs index 2621933697..d0b5d95fef 100644 --- a/PrototypeStructChaining/ChainExtensions.cs +++ b/PrototypeStructChaining/ChainExtensions.cs @@ -5,16 +5,17 @@ namespace Silk.Net.Vulkan; public static class ChainExtensions { /// - /// Sets the next structure in a chain. + /// Replaces a structure in the chain (if present, and is false), or adds it to the end. /// /// The current chain - /// The next value in the chain + /// A reference to the structure to update + /// Always adds to the end of the chain, even if an equivalent structure is present. /// The type of the current chain - /// The type of the next value - /// A reference to the next value in the chain + /// The type of the value + /// A reference to the value value in the chain /// - /// WARNING: The supplied value will have it's own next ptr nulled. - /// Note that both the supplied chain, and the next value will have their `SType` correctly set. + /// Note that both the supplied chain, and the supplied value will have their `SType` correctly set. Further, + /// the supplied structure's will be overwritten. /// To use /// /// var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures @@ -32,42 +33,156 @@ public static class ChainExtensions /// .SetNext(ref accelerationStructureFeaturesKhr); /// /// - public static unsafe ref TNext SetNext(this ref TChain chain, ref TNext capture) - where TChain : struct, IChainable - where TNext : struct, IChainable + public static unsafe ref TChain SetNext(this ref TChain chain, ref TNext value, + bool alwaysAdd = false) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain { - capture.SetNext(); - var reference = Unsafe.AsPointer(ref capture); - chain.SetNext((void*) *(IntPtr*) &reference); - return ref capture; + // Ensure structure type of chain and value are set. + chain.StructureType(); + var structureType = value.StructureType(); + + // Find end of chain + var previousPtr = (Chain*) null; + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + var valuePtr = (Chain*) Unsafe.AsPointer(ref value); + do + { + var nextPtr = currentPtr->PNext; + if (!alwaysAdd && currentPtr->SType == structureType) + { + // We have an existing structure, replace it. + if (previousPtr is not null) previousPtr->PNext = valuePtr; + valuePtr->PNext = nextPtr; + + return ref chain; + } + + previousPtr = currentPtr; + currentPtr = nextPtr; + } while (currentPtr is not null); + + // Add value to end of chain + previousPtr->PNext = valuePtr; + valuePtr->PNext = null; + + return ref chain; } /// - /// Creates the next structure in a chain. + /// Returns the index of the in the , if present. + /// + /// The chain + /// The structure value + /// The type of the current chain + /// The type of the value + /// The zero-indexed index if found; otherwise -1. + public static unsafe int IndexOf(this ref TChain chain, ref TNext value) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain + { + // Ensure structure type of chain is set. + chain.StructureType(); + + var index = 0; + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + var valuePtr = (Chain*) Unsafe.AsPointer(ref value); + // Follow chain + do + { + if (currentPtr == valuePtr) + return index; + currentPtr = currentPtr->PNext; + index++; + } while (currentPtr is not null); + + return -1; + } + + /// + /// Adds a structure to the end of the chain. /// /// The current chain - /// The next value created in the chain + /// The structure added to the end of the chain /// The type of the current chain - /// The type of the next value - /// A reference to the newly created next value in the chain + /// The type of the structure to add + /// The reference to the chain. /// - /// Note that both the supplied chain, and the newly created next value will have their `SType` correctly set + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set /// To use specify the output type required, e.g.: /// /// PhysicalDeviceFeatures2 /// .Chain(out var features2) - /// .CreateNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) - /// .CreateNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + /// .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); /// + /// Note, the value is always added, even if an equivalent value is added in the chain already. Use + /// to only add if not already present. /// - public static unsafe ref TNext CreateNext(this ref TChain chain, out TNext capture) - where TChain : struct, IChainable - where TNext : struct, IChainable + public static unsafe ref TChain AddNext(this ref TChain chain, out TNext next) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain { - capture = default; - capture.SetNext(); - var reference = Unsafe.AsPointer(ref capture); - chain.SetNext((void*) *(IntPtr*) &reference); - return ref capture; + // Ensure structure type of chain is set. + chain.StructureType(); + + // Find end of chain + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + while (currentPtr->PNext is not null) currentPtr = currentPtr->PNext; + + // Create new entry and set it's structure type + next = default; + next.StructureType(); + currentPtr->PNext = (Chain*) Unsafe.AsPointer(ref next); + return ref chain; + } + + /// + /// Tries to add a structure to the end of the chain. + /// + /// The current chain + /// The structure added to the end of the chain + /// Whether the structure was actually added + /// The type of the current chain + /// The type of the structure to add + /// The reference to the chain. + /// + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .Chain(out var features2) + /// .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures, out var added); + /// + /// + public static unsafe ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain + { + // Ensure structure type of chain is set. + chain.StructureType(); + + // Create new entry and get it's structure type + next = default; + var structureType = next.StructureType(); + + // Follow chain + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + do + { + if (currentPtr->SType == structureType) + { + added = false; + return ref chain; + } + + var nextPtr = currentPtr->PNext; + if (nextPtr is null) break; + currentPtr = nextPtr; + } while (true); + + currentPtr->PNext = (Chain*) Unsafe.AsPointer(ref next); + added = true; + return ref chain; } } \ No newline at end of file diff --git a/PrototypeStructChaining/DeviceCreateInfo.cs b/PrototypeStructChaining/DeviceCreateInfo.cs index a38c141c22..4f7712d6e6 100644 --- a/PrototypeStructChaining/DeviceCreateInfo.cs +++ b/PrototypeStructChaining/DeviceCreateInfo.cs @@ -1,9 +1,6 @@ namespace Silk.Net.Vulkan; -public struct DeviceCreateInfo : - IChainable, - IChainable, - IChainable +public struct DeviceCreateInfo : IChainStart { /// public StructureType SType; @@ -32,19 +29,25 @@ public unsafe DeviceCreateInfo( // NOTE Truncated for example } - #region Chaining Support - public static unsafe ref DeviceCreateInfo Chain(out DeviceCreateInfo capture) + /// + /// Convenience method to start a chain. + /// + /// The newly created chain root + /// A reference to the newly created chain. + public static unsafe ref DeviceCreateInfo Chain( + out DeviceCreateInfo capture) { - capture = new DeviceCreateInfo(StructureType.DeviceCreateInfo); + capture = new DeviceCreateInfo( + StructureType.DeviceCreateInfo); return ref capture; } - public unsafe void SetNext(void* next = default) + /// + StructureType IStructuredType.StructureType() { - SType = StructureType.DeviceCreateInfo; - PNext = next; + return SType = StructureType.DeviceCreateInfo; } #endregion diff --git a/PrototypeStructChaining/IChainStart.cs b/PrototypeStructChaining/IChainStart.cs new file mode 100644 index 0000000000..a86e8db5ea --- /dev/null +++ b/PrototypeStructChaining/IChainStart.cs @@ -0,0 +1,10 @@ +namespace Silk.Net.Vulkan; + +/// +/// Marks a chainable struct as being allowed at the start of a chain. +/// +/// Any will have a corresponding static `Chain(out var chain)` +/// convenience method. +public interface IChainStart : IChainable +{ +} \ No newline at end of file diff --git a/PrototypeStructChaining/IChainable.cs b/PrototypeStructChaining/IChainable.cs index 1528c142bd..f33553d72c 100644 --- a/PrototypeStructChaining/IChainable.cs +++ b/PrototypeStructChaining/IChainable.cs @@ -3,16 +3,9 @@ namespace Silk.Net.Vulkan; /// /// Base interface for any struct that has can set the next value. /// -public interface IChainable -{ - unsafe void SetNext(void* next = default); -} - -/// -/// Generic interface indicating which structs can be set in the `PNext` value. -/// -/// A valid next structure -public interface IChainable : IChainable - where TNext : IChainable +/// Note that any structure marked must start with a +/// and a void* field. So that a pointer to it can be coerced +/// to a pointer to a . +public interface IChainable : IStructuredType { } \ No newline at end of file diff --git a/PrototypeStructChaining/IExtendsChain.cs b/PrototypeStructChaining/IExtendsChain.cs new file mode 100644 index 0000000000..360c2063c8 --- /dev/null +++ b/PrototypeStructChaining/IExtendsChain.cs @@ -0,0 +1,10 @@ +namespace Silk.Net.Vulkan; + +/// +/// Generic interface indicating which chain this type can be added to. +/// +/// A chain start structure. +public interface IExtendsChain : IChainable + where TChain : IChainable +{ +} \ No newline at end of file diff --git a/PrototypeStructChaining/IStructuredType.cs b/PrototypeStructChaining/IStructuredType.cs new file mode 100644 index 0000000000..79d9385017 --- /dev/null +++ b/PrototypeStructChaining/IStructuredType.cs @@ -0,0 +1,12 @@ +namespace Silk.Net.Vulkan; + +public interface IStructuredType +{ + /// + /// Gets the structured type's enum value. + /// + /// + /// Retrieving the also coerces it to the correct value. + /// + StructureType StructureType(); +} \ No newline at end of file diff --git a/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs b/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs index 05ec4692d4..9a2fa6ecf8 100644 --- a/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs +++ b/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs @@ -1,7 +1,8 @@ namespace Silk.Net.Vulkan; public struct PhysicalDeviceAccelerationStructureFeaturesKHR : - IChainable + IExtendsChain, + IExtendsChain { /// public StructureType SType; @@ -32,18 +33,10 @@ public unsafe PhysicalDeviceAccelerationStructureFeaturesKHR( #region Chaining Support - public static unsafe ref PhysicalDeviceAccelerationStructureFeaturesKHR Chain( - out PhysicalDeviceAccelerationStructureFeaturesKHR capture) + /// + StructureType IStructuredType.StructureType() { - capture = new PhysicalDeviceAccelerationStructureFeaturesKHR(StructureType - .PhysicalDeviceAccelerationStructureFeaturesKhr); - return ref capture; - } - - public unsafe void SetNext(void* next = default) - { - SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; - PNext = next; + return SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; } #endregion diff --git a/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs b/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs index ebeeadf515..5f30fcd144 100644 --- a/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs +++ b/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs @@ -1,7 +1,8 @@ namespace Silk.Net.Vulkan; public struct PhysicalDeviceDescriptorIndexingFeatures : - IChainable + IExtendsChain, + IExtendsChain { /// public StructureType SType; @@ -32,18 +33,10 @@ public unsafe PhysicalDeviceDescriptorIndexingFeatures( #region Chaining Support - public static unsafe ref PhysicalDeviceDescriptorIndexingFeatures Chain( - out PhysicalDeviceDescriptorIndexingFeatures capture) + /// + StructureType IStructuredType.StructureType() { - capture = new PhysicalDeviceDescriptorIndexingFeatures( - StructureType.PhysicalDeviceDescriptorIndexingFeaturesExt); - return ref capture; - } - - public unsafe void SetNext(void* next = default) - { - SType = StructureType.PhysicalDeviceDescriptorIndexingFeaturesExt; - PNext = next; + return SType = StructureType.PhysicalDeviceDescriptorIndexingFeaturesExt; } #endregion diff --git a/PrototypeStructChaining/PhysicalDeviceFeatures2.cs b/PrototypeStructChaining/PhysicalDeviceFeatures2.cs index 8857e32c4e..8db163f074 100644 --- a/PrototypeStructChaining/PhysicalDeviceFeatures2.cs +++ b/PrototypeStructChaining/PhysicalDeviceFeatures2.cs @@ -1,17 +1,15 @@ -using System.Runtime.InteropServices; - -namespace Silk.Net.Vulkan; +namespace Silk.Net.Vulkan; public struct PhysicalDeviceFeatures2 : - IChainable, - IChainable + IChainStart, + IExtendsChain { public StructureType SType; public unsafe void* PNext; public PhysicalDeviceFeatures Features; public unsafe PhysicalDeviceFeatures2( - StructureType? sType = StructureType.PhysicalDeviceFeatures2Khr, + StructureType? sType = StructureType.PhysicalDeviceFeatures2, void* pNext = null, PhysicalDeviceFeatures? features = null) : this() @@ -27,16 +25,23 @@ public unsafe PhysicalDeviceFeatures2( #region Chaining Support - public static unsafe ref PhysicalDeviceFeatures2 Chain(out PhysicalDeviceFeatures2 capture) + /// + /// Convenience method to start a chain. + /// + /// The newly created chain root + /// A reference to the newly created chain. + public static unsafe ref PhysicalDeviceFeatures2 Chain( + out PhysicalDeviceFeatures2 capture) { - capture = new PhysicalDeviceFeatures2(StructureType.PhysicalDeviceFeatures2); + capture = new PhysicalDeviceFeatures2( + StructureType.PhysicalDeviceFeatures2); return ref capture; } - public unsafe void SetNext(void* next = default) + /// + StructureType IStructuredType.StructureType() { - SType = StructureType.PhysicalDeviceFeatures2; - PNext = next; + return SType = StructureType.PhysicalDeviceFeatures2; } #endregion diff --git a/PrototypeStructChaining/PrototypeStructChaining.csproj b/PrototypeStructChaining/PrototypeStructChaining.csproj index 9ba92105d5..cbc2a9595c 100644 --- a/PrototypeStructChaining/PrototypeStructChaining.csproj +++ b/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -10,14 +10,12 @@ - - - - - - - - + + + + + + diff --git a/Readme.md b/Readme.md index 45f379db20..6830c7cab7 100644 --- a/Readme.md +++ b/Readme.md @@ -19,23 +19,58 @@ All of these goals were met. The proposal provides for the following usage patterns: -### CreateNext +### Chain Building -The most common use case is to create an empty structure to be populated by the Vulkan API, this can now be done like so: +You can happily create the start of a chain as usual, and it's `SType` will be coerced when you start using it as a chain: +```csharp +var createInfo = new DeviceCreateInfo +{ + Flags = 1U +}; +// When you call any chaining method it will set the chain's SType automatically. +createinfo.AddNext... +``` + +-in many cases, we only want to create a default structure for population by the API. To do so, we use the static `Chain` +method like so: +```csharp +PhysicalDeviceFeatures2.Chain(out var features2) +``` + +This has several advantages: +- The method is only available for structures that are valid at the start of a chain; providing compile-time validation. +- The structure's `SType` will be correctly set immediately. +- The syntax is fluent, and creates more readable code when used with the other chaining methods (see below). + +### AddNext + +The most common use case is to add an empty structure to the end of a chain for it to be populated by the Vulkan API, +this can now be done like so: ```csharp PhysicalDeviceFeatures2 - // The Chain method, is a convenient static, to provide a consistent syntax. .Chain(out var features2) // CreateNext will create an empty struct, with the correct SType (as well as ensuring the - // caller SType is coerced correctly. - .CreateNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) - .CreateNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + // chain's SType is set correctly). + .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); ``` -We start by using the static `Chain` method, this is a convenience method that is not required, but it provides a more readable style. +Each method `out` puts a struct into the local stackframe for querying once populated, and the pointers point to this +local variable. Despite generics and interfaces being used, the chain methods avoid the heap entirely. + +### TryAddNext -Each method `out`puts a struct into the local stackframe for querying once populated. Despite generics and interface being used, boxing doesn't not occur. +You may only want to add a structure if it doesn't already exist in the chain, this can be done with `TryAddNext`, e.g.: + +```csharp +PhysicalDeviceFeatures2 + .Chain(out var features2) + .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + // As there is already a PhysicalDeviceDescriptorIndexingFeatures structure the following + // will not add anything to the chain and `added` will be `false`. + .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures2, out bool added); +``` ### SetNext @@ -58,29 +93,66 @@ PhysicalDeviceFeatures2 .SetNext(ref accelerationStructureFeaturesKhr); ``` -*NOTE* you can mix and match `CreateNext` and `SetNext` in the same chain. - -### Without Chain +*NOTE* you can mix and match `AddNext` and `SetNext` (and any chaining method) in the same method chain. -The use of the `Chain` method is entirely optional, for example if we wish to +By default, `SetNext` will replace any item in the chain with a matching `SType`, this behaviour can be changed by setting the optional +`alwaysAdd` parameter to `true`; ```csharp -// We don't have to use the Chain() pattern, as we can start with an existing struct -var createInfo = new DeviceCreateInfo +var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures { - Flags = 1U + ShaderInputAttachmentArrayDynamicIndexing = true +}; +var indexingFeatures2 = new PhysicalDeviceDescriptorIndexingFeatures +{ + ShaderInputAttachmentArrayDynamicIndexing = false }; -// However, note that CreateNext will still coerce the SType of createInfo. -createInfo.CreateNext(out PhysicalDeviceFeatures2 features2); +var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKHR +{ + AccelerationStructure = true +}; + +PhysicalDeviceFeatures2 + .Chain(out var features2) + .SetNext(ref indexingFeatures) + // This will add the second 'indexingFeatures' struct, even though one is already present in the chain. + .SetNext(ref indexingFeatures2, true); ``` +### IndexOf + +Sometimes it's useful to know if a structure you previously supplied is still in a chain, this can be done with `IndexOf`, +which returns a non-negative index (zero-indexed) if the structure is found, eg.: + +```csharp +PhysicalDeviceFeatures2 + .Chain(out var features2) + .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + +// Check indices +Assert.Equal(1, features2.IndexOf(ref indexingFeatures)); +Assert.Equal(2, features2.IndexOf(ref accelerationStructureFeaturesKhr)); +``` + +## Features + +* All the chaining methods are only available on the structures that implement `IChainStart`, i.e. the structures that the +Vulkan specification says can start a chain. +* All the chaining methods ensure the chain, and any supplied structures, have their `SType` correctly set. +* All the chaining methods will only accept a structure that is valid in the chain being extended, as per the Vulkan specification. +* The chaining methods do not box structures, or add anything to the heap. + ## Changes required * Add the `IChainable` and `IChainable` interfaces. * Add the `ChainExtensions` extension methods `SetNext` and `CreateNext`. * Add the small instance `void SetNext(void*)` method to each structure (this is required). -* Add the small static `Chain` method to each structure (note, this is optional sugar, allowing for 'single statement' building). -* Add `IChainable` interfaces to every chainable struct to indicate each valid structure accepted by `PNext`, eg.: +* Add the small static `Chain` method to each structure (note, this is optional sugar, allowing for 'single statement' + building). +* Add `IChainable` interfaces to every chainable struct to indicate each valid structure accepted by `PNext` + , eg.: + ```csharp public struct DeviceCreateInfo : IChainable, From aea15c9ced82ccd8dc7d1309bda1b04e22e0520c Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Fri, 5 Nov 2021 13:41:24 +0000 Subject: [PATCH 07/34] chore: Updated readme.md Updated `Changes Required` section. --- Readme.md | 54 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/Readme.md b/Readme.md index 6830c7cab7..631d78c0e7 100644 --- a/Readme.md +++ b/Readme.md @@ -21,7 +21,9 @@ The proposal provides for the following usage patterns: ### Chain Building -You can happily create the start of a chain as usual, and it's `SType` will be coerced when you start using it as a chain: +You can happily create the start of a chain as usual, and it's `SType` will be coerced when you start using it as a +chain: + ```csharp var createInfo = new DeviceCreateInfo { @@ -31,13 +33,16 @@ var createInfo = new DeviceCreateInfo createinfo.AddNext... ``` --in many cases, we only want to create a default structure for population by the API. To do so, we use the static `Chain` +-in many cases, we only want to create a default structure for population by the API. To do so, we use the +static `Chain` method like so: + ```csharp PhysicalDeviceFeatures2.Chain(out var features2) ``` This has several advantages: + - The method is only available for structures that are valid at the start of a chain; providing compile-time validation. - The structure's `SType` will be correctly set immediately. - The syntax is fluent, and creates more readable code when used with the other chaining methods (see below). @@ -95,7 +100,8 @@ PhysicalDeviceFeatures2 *NOTE* you can mix and match `AddNext` and `SetNext` (and any chaining method) in the same method chain. -By default, `SetNext` will replace any item in the chain with a matching `SType`, this behaviour can be changed by setting the optional +By default, `SetNext` will replace any item in the chain with a matching `SType`, this behaviour can be changed by +setting the optional `alwaysAdd` parameter to `true`; ```csharp @@ -121,8 +127,8 @@ PhysicalDeviceFeatures2 ### IndexOf -Sometimes it's useful to know if a structure you previously supplied is still in a chain, this can be done with `IndexOf`, -which returns a non-negative index (zero-indexed) if the structure is found, eg.: +Sometimes it's useful to know if a structure you previously supplied is still in a chain, this can be done +with `IndexOf`, which returns a non-negative index (zero-indexed) if the structure is found, eg.: ```csharp PhysicalDeviceFeatures2 @@ -137,26 +143,32 @@ Assert.Equal(2, features2.IndexOf(ref accelerationStructureFeaturesKhr)); ## Features -* All the chaining methods are only available on the structures that implement `IChainStart`, i.e. the structures that the -Vulkan specification says can start a chain. +* All the chaining methods are only available on the structures that implement `IChainStart`, i.e. the structures that + the Vulkan specification says can start a chain. * All the chaining methods ensure the chain, and any supplied structures, have their `SType` correctly set. -* All the chaining methods will only accept a structure that is valid in the chain being extended, as per the Vulkan specification. +* All the chaining methods will only accept a structure that is valid in the chain being extended, as per the Vulkan + specification. * The chaining methods do not box structures, or add anything to the heap. ## Changes required -* Add the `IChainable` and `IChainable` interfaces. -* Add the `ChainExtensions` extension methods `SetNext` and `CreateNext`. -* Add the small instance `void SetNext(void*)` method to each structure (this is required). -* Add the small static `Chain` method to each structure (note, this is optional sugar, allowing for 'single statement' - building). -* Add `IChainable` interfaces to every chainable struct to indicate each valid structure accepted by `PNext` - , eg.: +* Add the new `IStructureType`, `IChainable`, `IChainStart`, `IExtendChain` interfaces. +* Add the new `Chain` structure. +* Add the `ChainExtensions` extension methods `SetNext`, `AddNew`, `IndexOf`, `AddNext` and `TryAddNext`. +* Add the small instance `StructureType IStructuredType.StructureType()` method to `IChainable` structure. +* Add the `IChainStart` interface and the small static `Chain` method to any structure that can be used as the start of + a chain. +* Add `IExtendsChain` interfaces to any structures that can extend a chain. -```csharp -public struct DeviceCreateInfo : - IChainable, - IChainable, - IChainable ... -``` +Note that the [Vulkan XML](https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/registry/vk.xml) does +include the `structextends` attribute on each structure that directly maps to the `IExtendsChain` interfaces that +need to be added. However, to add the `IChainStart` interface (and it's associated method), these structures have to be +marked as a chain start whenever we see a structure extending them. + +Although it is possible to not use a design that does not make use of `IChainStart` the following functionality is lost: + +* The `Chain` method will appear on all chainable structures, even when they don't represent the start of a chain. +* All extension methods will appear on all chainable structures, even when they are not the start. +* Indexing, adding, etc. can't be guaranteed to be scanning from the start of the chain. +As adding `IChainStart` requires relatively simple logic I believe it's worth including. \ No newline at end of file From eca1dd218f06687cb84ae711de7e9f9f4e23663a Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Fri, 5 Nov 2021 19:38:19 +0000 Subject: [PATCH 08/34] feat: Added ManagedChain * ManagedChain holds structures in unmanaged memory, preventing their movement, and it can be safely held on the heap itself. * It allows for easy modification and manipulation of the chain. --- .../PrototypeStructChaining.Test.csproj | 10 +- .../TestManagedChains.cs | 104 ++++++++++++++++ PrototypeStructChaining/ManagedChain.cs | 116 ++++++++++++++++++ .../PrototypeStructChaining.csproj | 13 +- Readme.md | 77 +++++++++++- 5 files changed, 308 insertions(+), 12 deletions(-) create mode 100644 PrototypeStructChaining.Test/TestManagedChains.cs create mode 100644 PrototypeStructChaining/ManagedChain.cs diff --git a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj index 9353923378..c61c1205b8 100644 --- a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj +++ b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj @@ -10,9 +10,9 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -24,11 +24,11 @@ - + - + diff --git a/PrototypeStructChaining.Test/TestManagedChains.cs b/PrototypeStructChaining.Test/TestManagedChains.cs new file mode 100644 index 0000000000..9274586934 --- /dev/null +++ b/PrototypeStructChaining.Test/TestManagedChains.cs @@ -0,0 +1,104 @@ +using Silk.Net.Vulkan; +using Xunit; + +namespace PrototypeStructChaining.Test; + +public class TestManagedChains +{ + [Fact] + public unsafe void TestManagedChain() + { + using var chain = new ManagedChain(); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); + Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + } + + [Fact] + public unsafe void TestManagedChainReplaceHead() + { + using var chain = + new ManagedChain(); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.DeviceCreateInfo, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Item1.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); + Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + + Assert.Equal(0U, chain.Head.Flags); + + var headPtr = chain.HeadPtr; + + // Get the current head + var head = chain.Head; + // Update the flags + head.Flags = 1U; + // Update the chain + chain.Head = head; + + Assert.Equal(1U, chain.Head.Flags); + + // The head ptr should not change, we overwrite it with the new value + Assert.Equal((nint) headPtr, (nint) chain.HeadPtr); + // But the next pointer should not change + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + } + + [Fact] + public unsafe void TestManagedChainReplaceMiddle() + { + using var chain = new ManagedChain(item1: new PhysicalDeviceDescriptorIndexingFeatures + { + // We can set any non-default values, note we do not need to set SType or PNext + // indeed they will be overwritten. + ShaderInputAttachmentArrayDynamicIndexing = true + }); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); + Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + + // Check our value was set + Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + var item1Ptr = chain.Item1Ptr; + + // Overwrite Item1 + chain.Item1 = new PhysicalDeviceDescriptorIndexingFeatures + { + // Again we do not need to set SType or PNext, which will be set to the correct values + ShaderInputAttachmentArrayDynamicIndexing = false + }; + + // Check our value was cleared + Assert.False(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + // Note all the pointers are still correct (and have not changed) + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); + Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + + // As is the SType + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + } +} \ No newline at end of file diff --git a/PrototypeStructChaining/ManagedChain.cs b/PrototypeStructChaining/ManagedChain.cs new file mode 100644 index 0000000000..f679b82189 --- /dev/null +++ b/PrototypeStructChaining/ManagedChain.cs @@ -0,0 +1,116 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Silk.NET.Core.Native; + +namespace Silk.Net.Vulkan; + +// This should be autogenerated like Tuple<...>, only showing 3 arg type... + +public unsafe class ManagedChain : IDisposable +where TChain : struct, IChainStart +where T1 : struct, IExtendsChain +where T2 : struct, IExtendsChain +{ + private IntPtr _headPtr; + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets the second item in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + + private IntPtr _item2Ptr; + /// + /// Gets a pointer to the third item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets the third item in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The first item. + /// The second item. + /// The third item. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default) + { + _headPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*)_headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*)_item1Ptr)->PNext = (Chain*) _item2Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + Marshal.DestroyStructure((IntPtr)headPtr); + Marshal.FreeHGlobal(headPtr); + + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure((IntPtr)item1Ptr); + Marshal.FreeHGlobal(item1Ptr); + + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure((IntPtr)item2Ptr); + Marshal.FreeHGlobal(item2Ptr); + } +} \ No newline at end of file diff --git a/PrototypeStructChaining/PrototypeStructChaining.csproj b/PrototypeStructChaining/PrototypeStructChaining.csproj index cbc2a9595c..a9a068a1b9 100644 --- a/PrototypeStructChaining/PrototypeStructChaining.csproj +++ b/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -10,12 +10,13 @@ - - - - - - + + + + + + + diff --git a/Readme.md b/Readme.md index 631d78c0e7..4bfa96c781 100644 --- a/Readme.md +++ b/Readme.md @@ -171,4 +171,79 @@ Although it is possible to not use a design that does not make use of `IChainSta * All extension methods will appear on all chainable structures, even when they are not the start. * Indexing, adding, etc. can't be guaranteed to be scanning from the start of the chain. -As adding `IChainStart` requires relatively simple logic I believe it's worth including. \ No newline at end of file +As adding `IChainStart` requires relatively simple logic I believe it's worth including. + +# Extension + +## ManagedChain + +Sometimes it is desirable to keep the structures around on the heap. To facilitate that you can use +the `ManagedChain` +types. Like `Tuple` et al, these support up to chain size 16. They should be disposed when finished with. + +Example: + +```csharp +using var chain = new ManagedChain(); + +// Ensure all STypes set correctly +Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); +Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain.Item2.SType); + +// Ensure pointers set correctly +Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); +Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); +Assert.Equal((nint) 0, (nint) chain.Item2.PNext); +``` + +The structures are held in unmanaged memory, preventing movement by the GC, and ensuring that the ptrs remain fixed. + +We can easily modify any value in the `ManagedChain`, and it will maintain the ptrs automatically, e.g.: + +```csharp +using var chain = new ManagedChain(item1: new PhysicalDeviceDescriptorIndexingFeatures +{ + // We can set any non-default values, note we do not need to set SType or PNext + // indeed they will be overwritten. + ShaderInputAttachmentArrayDynamicIndexing = true +}); + +// Ensure all STypes set correctly +Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); +Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain.Item2.SType); + +// Ensure pointers set correctly +Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); +Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); +Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + +// Check our value was set +Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + +var item1Ptr = chain.Item1Ptr; + +// Overwrite Item1 +chain.Item1 = new PhysicalDeviceDescriptorIndexingFeatures +{ + // Again we do not need to set SType or PNext, which will be set to the correct values + ShaderInputAttachmentArrayDynamicIndexing = false +}; + +// Check our value was cleared +Assert.False(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + +// Note all the pointers are still correct (and have not changed) +Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); +Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); +Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + +// As is the SType +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); +``` + +**Note** When we update any item in the chain it overwrites the existing memory, so the ptrs remain fixed. It also +ensures the PNext value is maintained. \ No newline at end of file From 389c1f997098fb55401e25d861ddfe69ff619a72 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Fri, 5 Nov 2021 19:48:03 +0000 Subject: [PATCH 09/34] feat: Added static `ManagedChain.Create` example --- PrototypeStructChaining/ManagedChain.cs | 23 +++++++++++++++++++++++ Readme.md | 4 +++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/PrototypeStructChaining/ManagedChain.cs b/PrototypeStructChaining/ManagedChain.cs index f679b82189..b04198a201 100644 --- a/PrototypeStructChaining/ManagedChain.cs +++ b/PrototypeStructChaining/ManagedChain.cs @@ -4,6 +4,29 @@ namespace Silk.Net.Vulkan; +/// +/// Static class for creating Managed Chains. +/// +public static class ManagedChain +{ + /// + /// Creates a new with 3 items. + /// + /// The first item. + /// The second item. + /// The third item. + /// The chain type + /// Type of the second item. + /// Type of the third item. + /// + public static ManagedChain Create(TChain head = default, T1 item1 = default, + T2 item2 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + => new ManagedChain(head, item1, item2); +} + // This should be autogenerated like Tuple<...>, only showing 3 arg type... public unsafe class ManagedChain : IDisposable diff --git a/Readme.md b/Readme.md index 4bfa96c781..a2e8f5b431 100644 --- a/Readme.md +++ b/Readme.md @@ -246,4 +246,6 @@ Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1 ``` **Note** When we update any item in the chain it overwrites the existing memory, so the ptrs remain fixed. It also -ensures the PNext value is maintained. \ No newline at end of file +ensures the PNext value is maintained. + +You can also use the `ManagedChain.Create(...)` static methods to create `ManagedChain`s. \ No newline at end of file From e7f047d5a14cd97951223b92a7f54170edcac8ae Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Fri, 5 Nov 2021 19:56:16 +0000 Subject: [PATCH 10/34] feat: ManagedChain uses a single memory block. --- PrototypeStructChaining/ManagedChain.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/PrototypeStructChaining/ManagedChain.cs b/PrototypeStructChaining/ManagedChain.cs index b04198a201..00f6bac530 100644 --- a/PrototypeStructChaining/ManagedChain.cs +++ b/PrototypeStructChaining/ManagedChain.cs @@ -105,16 +105,21 @@ public T2 Item2 /// The third item. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default) { - _headPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); + + _item1Ptr = _headPtr + headSize; item1.StructureType(); Marshal.StructureToPtr(item1, _item1Ptr, false); ((Chain*)_headPtr)->PNext = (Chain*) _item1Ptr; - _item2Ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); + _item2Ptr = _item1Ptr + item1Size; item2.StructureType(); Marshal.StructureToPtr(item2, _item2Ptr, false); ((Chain*)_item1Ptr)->PNext = (Chain*) _item2Ptr; @@ -126,14 +131,10 @@ public void Dispose() var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); if (headPtr == IntPtr.Zero) return; Marshal.DestroyStructure((IntPtr)headPtr); - Marshal.FreeHGlobal(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); Marshal.DestroyStructure((IntPtr)item1Ptr); - Marshal.FreeHGlobal(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); Marshal.DestroyStructure((IntPtr)item2Ptr); - Marshal.FreeHGlobal(item2Ptr); + Marshal.FreeHGlobal(headPtr); } } \ No newline at end of file From ff031f66fb1ec615339a241cf441fcc04334b443 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Fri, 5 Nov 2021 20:56:25 +0000 Subject: [PATCH 11/34] feat: Added T4 template. `ManagedChain` now supports 2-16 chain items. --- .../PrototypeStructChaining.Test.csproj | 10 +- .../TestManagedChains.cs | 8 +- PrototypeStructChaining/ManagedChain.cs | 5173 ++++++++++++++++- PrototypeStructChaining/ManagedChain.tt | 259 + .../PrototypeStructChaining.csproj | 15 + 5 files changed, 5423 insertions(+), 42 deletions(-) create mode 100644 PrototypeStructChaining/ManagedChain.tt diff --git a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj index c61c1205b8..9353923378 100644 --- a/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj +++ b/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj @@ -10,9 +10,9 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -24,11 +24,11 @@ - + - + diff --git a/PrototypeStructChaining.Test/TestManagedChains.cs b/PrototypeStructChaining.Test/TestManagedChains.cs index 9274586934..0456d6e642 100644 --- a/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/PrototypeStructChaining.Test/TestManagedChains.cs @@ -82,22 +82,22 @@ public unsafe void TestManagedChainReplaceMiddle() Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); var item1Ptr = chain.Item1Ptr; - + // Overwrite Item1 chain.Item1 = new PhysicalDeviceDescriptorIndexingFeatures { // Again we do not need to set SType or PNext, which will be set to the correct values ShaderInputAttachmentArrayDynamicIndexing = false }; - + // Check our value was cleared Assert.False(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); - + // Note all the pointers are still correct (and have not changed) Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); Assert.Equal((nint) 0, (nint) chain.Item2.PNext); - + // As is the SType Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); } diff --git a/PrototypeStructChaining/ManagedChain.cs b/PrototypeStructChaining/ManagedChain.cs index 00f6bac530..b98c22090c 100644 --- a/PrototypeStructChaining/ManagedChain.cs +++ b/PrototypeStructChaining/ManagedChain.cs @@ -1,6 +1,5 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Silk.NET.Core.Native; namespace Silk.Net.Vulkan; @@ -10,36 +9,654 @@ namespace Silk.Net.Vulkan; public static class ManagedChain { /// - /// Creates a new with 3 items. + /// Creates a new with 2 items. + /// + /// The head of the chain. + /// Item 1. + /// The chain type + /// Type of Item 1. + /// A new with 2 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + { + return new(head, item1); + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// A new with 3 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + { + return new(head, item1, item2); + } + + /// + /// Creates a new with 4 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// A new with 4 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + { + return new(head, item1, item2, item3); + } + + /// + /// Creates a new with 5 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// A new with 5 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4); + } + + /// + /// Creates a new with 6 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// A new with 6 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5); + } + + /// + /// Creates a new with 7 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// A new with 7 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6); + } + + /// + /// Creates a new with 8 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// A new with 8 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7); + } + + /// + /// Creates a new with 9 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// A new with 9 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8); + } + + /// + /// Creates a new with 10 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// A new with 10 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9); + } + + /// + /// Creates a new with 11 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// A new with 11 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10); + } + + /// + /// Creates a new with 12 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// A new with 12 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11); + } + + /// + /// Creates a new with 13 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// A new with 13 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12); + } + + /// + /// Creates a new with 14 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// A new with 14 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); + } + + /// + /// Creates a new with 15 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// A new with 15 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); + } + + /// + /// Creates a new with 16 items. /// - /// The first item. - /// The second item. - /// The third item. + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// Item 15. /// The chain type - /// Type of the second item. - /// Type of the third item. - /// - public static ManagedChain Create(TChain head = default, T1 item1 = default, - T2 item2 = default) + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. + /// A new with 16 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain - => new ManagedChain(head, item1, item2); + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); + } + } -// This should be autogenerated like Tuple<...>, only showing 3 arg type... +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + public ManagedChain(TChain head = default, T1 item1 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. public unsafe class ManagedChain : IDisposable -where TChain : struct, IChainStart -where T1 : struct, IExtendsChain -where T2 : struct, IExtendsChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain { private IntPtr _headPtr; + /// /// Gets a pointer to the current head. /// public Chain* HeadPtr => (Chain*) _headPtr; - + /// /// Gets or sets the head of the chain. /// @@ -56,15 +673,16 @@ public TChain Head } private IntPtr _item1Ptr; + /// /// Gets a pointer to the second item in the chain. /// public Chain* Item1Ptr => (Chain*) _item1Ptr; - + /// - /// Gets or sets the second item in the chain. + /// Gets or sets item #1 in the chain. /// - public T1 Item1 + public T1 Item1 { get => Unsafe.AsRef((Chain*) _item1Ptr); set @@ -75,15 +693,15 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } - private IntPtr _item2Ptr; + /// - /// Gets a pointer to the third item in the chain. + /// Gets a pointer to the second item in the chain. /// public Chain* Item2Ptr => (Chain*) _item2Ptr; - + /// - /// Gets or sets the third item in the chain. + /// Gets or sets item #2 in the chain. /// public T2 Item2 { @@ -100,9 +718,9 @@ public T2 Item2 /// /// Creates a new with 3 items. /// - /// The first item. - /// The second item. - /// The third item. + /// The head of the chain. + /// Item 1. + /// Item 2. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default) { // Calculate memory requirements @@ -117,12 +735,12 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul _item1Ptr = _headPtr + headSize; item1.StructureType(); Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*)_headPtr)->PNext = (Chain*) _item1Ptr; - + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + _item2Ptr = _item1Ptr + item1Size; item2.StructureType(); Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*)_item1Ptr)->PNext = (Chain*) _item2Ptr; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; } /// @@ -130,11 +748,4500 @@ public void Dispose() { var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); if (headPtr == IntPtr.Zero) return; - Marshal.DestroyStructure((IntPtr)headPtr); + + // Destroy all structures + Marshal.DestroyStructure(headPtr); var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure((IntPtr)item1Ptr); + Marshal.DestroyStructure(item1Ptr); var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure((IntPtr)item2Ptr); + Marshal.DestroyStructure(item2Ptr); + + // Free memory block Marshal.FreeHGlobal(headPtr); } -} \ No newline at end of file +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + private IntPtr _item11Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item11Ptr => (Chain*) _item11Ptr; + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef((Chain*) _item11Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + private IntPtr _item11Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item11Ptr => (Chain*) _item11Ptr; + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef((Chain*) _item11Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; + } + } + private IntPtr _item12Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item12Ptr => (Chain*) _item12Ptr; + + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef((Chain*) _item12Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item12Ptr)->PNext; + Marshal.StructureToPtr(value, _item12Ptr, true); + ((Chain*) _item12Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item12Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +/// Type of Item 13. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + private IntPtr _item11Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item11Ptr => (Chain*) _item11Ptr; + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef((Chain*) _item11Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; + } + } + private IntPtr _item12Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item12Ptr => (Chain*) _item12Ptr; + + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef((Chain*) _item12Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item12Ptr)->PNext; + Marshal.StructureToPtr(value, _item12Ptr, true); + ((Chain*) _item12Ptr)->PNext = nextPtr; + } + } + private IntPtr _item13Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item13Ptr => (Chain*) _item13Ptr; + + /// + /// Gets or sets item #13 in the chain. + /// + public T13 Item13 + { + get => Unsafe.AsRef((Chain*) _item13Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item13Ptr)->PNext; + Marshal.StructureToPtr(value, _item13Ptr, true); + ((Chain*) _item13Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + item13.StructureType(); + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item12Ptr); + var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item13Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +/// Type of Item 13. +/// Type of Item 14. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + private IntPtr _item11Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item11Ptr => (Chain*) _item11Ptr; + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef((Chain*) _item11Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; + } + } + private IntPtr _item12Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item12Ptr => (Chain*) _item12Ptr; + + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef((Chain*) _item12Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item12Ptr)->PNext; + Marshal.StructureToPtr(value, _item12Ptr, true); + ((Chain*) _item12Ptr)->PNext = nextPtr; + } + } + private IntPtr _item13Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item13Ptr => (Chain*) _item13Ptr; + + /// + /// Gets or sets item #13 in the chain. + /// + public T13 Item13 + { + get => Unsafe.AsRef((Chain*) _item13Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item13Ptr)->PNext; + Marshal.StructureToPtr(value, _item13Ptr, true); + ((Chain*) _item13Ptr)->PNext = nextPtr; + } + } + private IntPtr _item14Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item14Ptr => (Chain*) _item14Ptr; + + /// + /// Gets or sets item #14 in the chain. + /// + public T14 Item14 + { + get => Unsafe.AsRef((Chain*) _item14Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item14Ptr)->PNext; + Marshal.StructureToPtr(value, _item14Ptr, true); + ((Chain*) _item14Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + var item14Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + item13.StructureType(); + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + item14.StructureType(); + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item12Ptr); + var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item13Ptr); + var item14Ptr = Interlocked.Exchange(ref _item14Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item14Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +/// Type of Item 13. +/// Type of Item 14. +/// Type of Item 15. +public unsafe class ManagedChain : IDisposable + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + private IntPtr _item11Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item11Ptr => (Chain*) _item11Ptr; + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef((Chain*) _item11Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; + } + } + private IntPtr _item12Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item12Ptr => (Chain*) _item12Ptr; + + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef((Chain*) _item12Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item12Ptr)->PNext; + Marshal.StructureToPtr(value, _item12Ptr, true); + ((Chain*) _item12Ptr)->PNext = nextPtr; + } + } + private IntPtr _item13Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item13Ptr => (Chain*) _item13Ptr; + + /// + /// Gets or sets item #13 in the chain. + /// + public T13 Item13 + { + get => Unsafe.AsRef((Chain*) _item13Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item13Ptr)->PNext; + Marshal.StructureToPtr(value, _item13Ptr, true); + ((Chain*) _item13Ptr)->PNext = nextPtr; + } + } + private IntPtr _item14Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item14Ptr => (Chain*) _item14Ptr; + + /// + /// Gets or sets item #14 in the chain. + /// + public T14 Item14 + { + get => Unsafe.AsRef((Chain*) _item14Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item14Ptr)->PNext; + Marshal.StructureToPtr(value, _item14Ptr, true); + ((Chain*) _item14Ptr)->PNext = nextPtr; + } + } + private IntPtr _item15Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item15Ptr => (Chain*) _item15Ptr; + + /// + /// Gets or sets item #15 in the chain. + /// + public T15 Item15 + { + get => Unsafe.AsRef((Chain*) _item15Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item15Ptr)->PNext; + Marshal.StructureToPtr(value, _item15Ptr, true); + ((Chain*) _item15Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// Item 15. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + var item14Size = Marshal.SizeOf(); + var item15Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size + item15Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + item13.StructureType(); + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + item14.StructureType(); + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + + _item15Ptr = _item14Ptr + item14Size; + item15.StructureType(); + Marshal.StructureToPtr(item15, _item15Ptr, false); + ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item12Ptr); + var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item13Ptr); + var item14Ptr = Interlocked.Exchange(ref _item14Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item14Ptr); + var item15Ptr = Interlocked.Exchange(ref _item15Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item15Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} diff --git a/PrototypeStructChaining/ManagedChain.tt b/PrototypeStructChaining/ManagedChain.tt new file mode 100644 index 0000000000..ea244293d7 --- /dev/null +++ b/PrototypeStructChaining/ManagedChain.tt @@ -0,0 +1,259 @@ +<#@ template language="C#" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<# + var maximumItems = 16; + + string parameterDocs(int index, string prefix) + { + var builder = new StringBuilder(prefix); + builder.Append("The head of the chain."); + for (var i = 1; i < index; i++) + { + builder + .AppendLine() + .Append(prefix) + .Append("Item ") + .Append(i) + .Append("."); + } + return builder.ToString(); + } + + string parameterTypeDocs(int index, string prefix) + { + var builder = new StringBuilder(prefix); + builder.Append("The chain type"); + for (var i = 1; i < index; i++) + { + builder + .AppendLine() + .Append(prefix) + .Append("Type of Item ") + .Append(i) + .Append("."); + } + return builder.ToString(); + } + + string typeList(int index) + { + var builder = new StringBuilder("TChain"); + for (var i = 1; i < index; i++) + { + builder + .Append(", T") + .Append(i); + } + return builder.ToString(); + } + + string paramList(int index) + { + var builder = new StringBuilder("TChain head = default"); + for (var i = 1; i < index; i++) + { + builder + .Append(", T") + .Append(i) + .Append(" item") + .Append(i) + .Append(" = default"); + } + return builder.ToString(); + } + + string argList(int index) + { + var builder = new StringBuilder("head"); + for (var i = 1; i < index; i++) + { + builder + .Append(", item") + .Append(i); + } + return builder.ToString(); + } + + string constraintList(int index, string prefix) + { + var builder = new StringBuilder(prefix); + builder.Append("where TChain : struct, IChainStart"); + for (var i = 1; i < index; i++) + { + builder + .AppendLine() + .Append(prefix) + .Append("where T") + .Append(i) + .Append(" : struct, IExtendsChain"); + } + return builder.ToString(); + } +#> +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Silk.Net.Vulkan; + +/// +/// Static class for creating Managed Chains. +/// +public static class ManagedChain +{ +<# + for (var i = 2; i <= maximumItems; i++) + { + var tList = typeList(i); +#> + /// + /// Creates a new with <#= i #> items. + /// +<#= parameterDocs(i, " /// ") #> +<#= parameterTypeDocs(i, " /// ") #> + /// A new with <#= i #> items. + public static ManagedChain<<#= tList #>> Create<<#= tList #>>(<#= paramList(i) #>) +<#= constraintList(i, " ") #> + { + return new(<#= argList(i) #>); + } + +<# + } // for (var 2 = 1; i <= maximumItems; i++) { +#> +} + +<# + for (var i = 2; i <= maximumItems; i++) + { + var tList = typeList(i); +#> +/// +/// A safely manages the pointers of a managed structure chain. +/// +<#= parameterTypeDocs(i, "/// ") #> +public unsafe class ManagedChain<<#= tList #>> : IDisposable +<#= constraintList(i, " ") #> +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + +<# + for (var j = 1; j < i; j++) + { +#> + private IntPtr _item<#= j #>Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item<#= j #>Ptr => (Chain*) _item<#= j #>Ptr; + + /// + /// Gets or sets item #<#= j #> in the chain. + /// + public T<#= j #> Item<#= j #> + { + get => Unsafe.AsRef>((Chain*) _item<#= j #>Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item<#= j #>Ptr)->PNext; + Marshal.StructureToPtr(value, _item<#= j #>Ptr, true); + ((Chain*) _item<#= j #>Ptr)->PNext = nextPtr; + } + } +<# + } // for (int j = 1; j < i; j++) { +#> + + /// + /// Creates a new with 3 items. + /// +<#= parameterDocs(i, " /// ") #> + public ManagedChain(<#= paramList(i) #>) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); +<# + for (var j = 1; j < i; j++) + { +#> + var item<#= j #>Size = Marshal.SizeOf>(); +<# + } // for (int j = 1; j < i; j++) { +#> + + _headPtr = Marshal.AllocHGlobal(headSize<# + for (var j = 1; j < i; j++) + { +#> + item<#= j #>Size<# + } // for (int j = 1; j < i; j++) { +#>); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); +<# + for (var j = 1; j < i; j++) + { + var prevItem = j > 1 + ? $"item{j - 1}" + : "head"; +#> + + _item<#= j #>Ptr = _<#= prevItem #>Ptr + <#= prevItem #>Size; + item<#= j #>.StructureType(); + Marshal.StructureToPtr(item<#= j #>, _item<#= j #>Ptr, false); + ((Chain*) _<#= prevItem #>Ptr)->PNext = (Chain*) _item<#= j #>Ptr; +<# + } // for (int j = 1; j < i; j++) { +#> + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); +<# + for (var j = 1; j < i; j++) + { +#> + var item<#=j#>Ptr = Interlocked.Exchange(ref _item<#=j#>Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item<#=j#>Ptr); +<# + } // for (int j = 1; j < i; j++) { +#> + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +<# + } // for (var i = 2; i <= maximumItems; i++) { +#> \ No newline at end of file diff --git a/PrototypeStructChaining/PrototypeStructChaining.csproj b/PrototypeStructChaining/PrototypeStructChaining.csproj index a9a068a1b9..6de1a80a99 100644 --- a/PrototypeStructChaining/PrototypeStructChaining.csproj +++ b/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -19,4 +19,19 @@ + + + TextTemplatingFileGenerator + ManagedChain.cs + + + + + + True + True + ManagedChain.tt + + + From dd2c1a8a716db11fe8d22639ed5ce0b5b3968743 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Fri, 5 Nov 2021 22:00:42 +0000 Subject: [PATCH 12/34] feat: Added `ManagedChain.Append` Can now easily append an item to an existing `ManagedChain` to efficiently create a new `ManagedChain`. --- .../TestManagedChains.cs | 37 + PrototypeStructChaining/ManagedChain.cs | 1134 ++++++++++++++++- PrototypeStructChaining/ManagedChain.tt | 92 +- Readme.md | 17 +- 4 files changed, 1226 insertions(+), 54 deletions(-) diff --git a/PrototypeStructChaining.Test/TestManagedChains.cs b/PrototypeStructChaining.Test/TestManagedChains.cs index 0456d6e642..e2dca905b8 100644 --- a/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/PrototypeStructChaining.Test/TestManagedChains.cs @@ -101,4 +101,41 @@ public unsafe void TestManagedChainReplaceMiddle() // As is the SType Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); } + + [Fact] + public unsafe void TestManagedChainAppend() + { + using var chain = new ManagedChain( + item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true}); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) 0, (nint) chain.Item1.PNext); + + // Check flag set + Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + using var newChain = chain.Append(); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, newChain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, newChain.Item1.SType); + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, newChain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) newChain.Item1Ptr, (nint) newChain.Head.PNext); + Assert.Equal((nint) newChain.Item2Ptr, (nint) newChain.Item1.PNext); + Assert.Equal((nint) 0, (nint) newChain.Item2.PNext); + + // Check flag still set + Assert.True(newChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + // Check we have new copies + Assert.NotEqual((nint) chain.HeadPtr, (nint) newChain.HeadPtr); + Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); + } } \ No newline at end of file diff --git a/PrototypeStructChaining/ManagedChain.cs b/PrototypeStructChaining/ManagedChain.cs index b98c22090c..26c14b2aad 100644 --- a/PrototypeStructChaining/ManagedChain.cs +++ b/PrototypeStructChaining/ManagedChain.cs @@ -604,7 +604,7 @@ public T1 Item1 } /// - /// Creates a new with 3 items. + /// Creates a new with 2 items. /// /// The head of the chain. /// Item 1. @@ -624,6 +624,21 @@ public ManagedChain(TChain head = default, T1 item1 = default) ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; } + /// + /// Creates a new with 3 items, by appending to + /// the end of this chain. + /// + /// Item 2. + /// Type of Item 2 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T2 item2 = default) + where T2: struct, IExtendsChain + { + return new ManagedChain(this, item2); + } + /// public void Dispose() { @@ -639,6 +654,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -716,7 +732,7 @@ public T2 Item2 } /// - /// Creates a new with 3 items. + /// Creates a new with 3 items. /// /// The head of the chain. /// Item 1. @@ -743,6 +759,53 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; } + /// + /// Creates a new with 3 items. + /// + /// The chain to append to. + /// Item 2. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T2 item2 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size; + var newSize = originalSize + item2Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + // Append the last structure + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + } + + /// + /// Creates a new with 4 items, by appending to + /// the end of this chain. + /// + /// Item 3. + /// Type of Item 3 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T3 item3 = default) + where T3: struct, IExtendsChain + { + return new ManagedChain(this, item3); + } + /// public void Dispose() { @@ -760,6 +823,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -860,7 +924,7 @@ public T3 Item3 } /// - /// Creates a new with 3 items. + /// Creates a new with 4 items. /// /// The head of the chain. /// Item 1. @@ -894,6 +958,57 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; } + /// + /// Creates a new with 4 items. + /// + /// The chain to append to. + /// Item 3. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T3 item3 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size; + var newSize = originalSize + item3Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + // Append the last structure + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + } + + /// + /// Creates a new with 5 items, by appending to + /// the end of this chain. + /// + /// Item 4. + /// Type of Item 4 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T4 item4 = default) + where T4: struct, IExtendsChain + { + return new ManagedChain(this, item4); + } + /// public void Dispose() { @@ -913,6 +1028,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -1036,7 +1152,7 @@ public T4 Item4 } /// - /// Creates a new with 3 items. + /// Creates a new with 5 items. /// /// The head of the chain. /// Item 1. @@ -1077,6 +1193,61 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; } + /// + /// Creates a new with 5 items. + /// + /// The chain to append to. + /// Item 4. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T4 item4 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size; + var newSize = originalSize + item4Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + // Append the last structure + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + } + + /// + /// Creates a new with 6 items, by appending to + /// the end of this chain. + /// + /// Item 5. + /// Type of Item 5 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T5 item5 = default) + where T5: struct, IExtendsChain + { + return new ManagedChain(this, item5); + } + /// public void Dispose() { @@ -1098,6 +1269,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -1244,7 +1416,7 @@ public T5 Item5 } /// - /// Creates a new with 3 items. + /// Creates a new with 6 items. /// /// The head of the chain. /// Item 1. @@ -1292,6 +1464,65 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; } + /// + /// Creates a new with 6 items. + /// + /// The chain to append to. + /// Item 5. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T5 item5 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size; + var newSize = originalSize + item5Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + // Append the last structure + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + } + + /// + /// Creates a new with 7 items, by appending to + /// the end of this chain. + /// + /// Item 6. + /// Type of Item 6 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T6 item6 = default) + where T6: struct, IExtendsChain + { + return new ManagedChain(this, item6); + } + /// public void Dispose() { @@ -1315,6 +1546,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -1484,7 +1716,7 @@ public T6 Item6 } /// - /// Creates a new with 3 items. + /// Creates a new with 7 items. /// /// The head of the chain. /// Item 1. @@ -1539,6 +1771,69 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; } + /// + /// Creates a new with 7 items. + /// + /// The chain to append to. + /// Item 6. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T6 item6 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size; + var newSize = originalSize + item6Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + // Append the last structure + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + } + + /// + /// Creates a new with 8 items, by appending to + /// the end of this chain. + /// + /// Item 7. + /// Type of Item 7 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T7 item7 = default) + where T7: struct, IExtendsChain + { + return new ManagedChain(this, item7); + } + /// public void Dispose() { @@ -1564,6 +1859,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -1756,7 +2052,7 @@ public T7 Item7 } /// - /// Creates a new with 3 items. + /// Creates a new with 8 items. /// /// The head of the chain. /// Item 1. @@ -1818,6 +2114,73 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; } + /// + /// Creates a new with 8 items. + /// + /// The chain to append to. + /// Item 7. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T7 item7 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size; + var newSize = originalSize + item7Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + // Append the last structure + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + } + + /// + /// Creates a new with 9 items, by appending to + /// the end of this chain. + /// + /// Item 8. + /// Type of Item 8 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T8 item8 = default) + where T8: struct, IExtendsChain + { + return new ManagedChain(this, item8); + } + /// public void Dispose() { @@ -1845,6 +2208,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -2060,7 +2424,7 @@ public T8 Item8 } /// - /// Creates a new with 3 items. + /// Creates a new with 9 items. /// /// The head of the chain. /// Item 1. @@ -2129,16 +2493,87 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; } - /// - public void Dispose() + /// + /// Creates a new with 9 items. + /// + /// The chain to append to. + /// Item 8. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T8 item8 = default) { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size; + var newSize = originalSize + item8Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + // Append the last structure + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + } + + /// + /// Creates a new with 10 items, by appending to + /// the end of this chain. + /// + /// Item 9. + /// Type of Item 9 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T9 item9 = default) + where T9: struct, IExtendsChain + { + return new ManagedChain(this, item9); + } + + /// + public void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); Marshal.DestroyStructure(item2Ptr); var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); @@ -2158,6 +2593,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -2396,7 +2832,7 @@ public T9 Item9 } /// - /// Creates a new with 3 items. + /// Creates a new with 10 items. /// /// The head of the chain. /// Item 1. @@ -2472,6 +2908,81 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; } + /// + /// Creates a new with 10 items. + /// + /// The chain to append to. + /// Item 9. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T9 item9 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size; + var newSize = originalSize + item9Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + // Append the last structure + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + } + + /// + /// Creates a new with 11 items, by appending to + /// the end of this chain. + /// + /// Item 10. + /// Type of Item 10 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T10 item10 = default) + where T10: struct, IExtendsChain + { + return new ManagedChain(this, item10); + } + /// public void Dispose() { @@ -2503,6 +3014,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -2764,7 +3276,7 @@ public T10 Item10 } /// - /// Creates a new with 3 items. + /// Creates a new with 11 items. /// /// The head of the chain. /// Item 1. @@ -2847,6 +3359,85 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; } + /// + /// Creates a new with 11 items. + /// + /// The chain to append to. + /// Item 10. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T10 item10 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size; + var newSize = originalSize + item10Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + // Append the last structure + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + } + + /// + /// Creates a new with 12 items, by appending to + /// the end of this chain. + /// + /// Item 11. + /// Type of Item 11 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T11 item11 = default) + where T11: struct, IExtendsChain + { + return new ManagedChain(this, item11); + } + /// public void Dispose() { @@ -2880,6 +3471,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -3164,7 +3756,7 @@ public T11 Item11 } /// - /// Creates a new with 3 items. + /// Creates a new with 12 items. /// /// The head of the chain. /// Item 1. @@ -3254,6 +3846,89 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; } + /// + /// Creates a new with 12 items. + /// + /// The chain to append to. + /// Item 11. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T11 item11 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size; + var newSize = originalSize + item11Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + // Append the last structure + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + } + + /// + /// Creates a new with 13 items, by appending to + /// the end of this chain. + /// + /// Item 12. + /// Type of Item 12 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T12 item12 = default) + where T12: struct, IExtendsChain + { + return new ManagedChain(this, item12); + } + /// public void Dispose() { @@ -3289,6 +3964,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -3596,7 +4272,7 @@ public T12 Item12 } /// - /// Creates a new with 3 items. + /// Creates a new with 13 items. /// /// The head of the chain. /// Item 1. @@ -3628,71 +4304,158 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item11Size = Marshal.SizeOf(); var item12Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + } + + /// + /// Creates a new with 13 items. + /// + /// The chain to append to. + /// Item 12. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T12 item12 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size; + var newSize = originalSize + item12Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; _item8Ptr = _item7Ptr + item7Size; - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; _item9Ptr = _item8Ptr + item8Size; - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; _item10Ptr = _item9Ptr + item9Size; - item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; _item11Ptr = _item10Ptr + item10Size; - item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; _item12Ptr = _item11Ptr + item11Size; + // Append the last structure item12.StructureType(); Marshal.StructureToPtr(item12, _item12Ptr, false); ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; } + /// + /// Creates a new with 14 items, by appending to + /// the end of this chain. + /// + /// Item 13. + /// Type of Item 13 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T13 item13 = default) + where T13: struct, IExtendsChain + { + return new ManagedChain(this, item13); + } + /// public void Dispose() { @@ -3730,6 +4493,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -4060,7 +4824,7 @@ public T13 Item13 } /// - /// Creates a new with 3 items. + /// Creates a new with 14 items. /// /// The head of the chain. /// Item 1. @@ -4164,6 +4928,97 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; } + /// + /// Creates a new with 14 items. + /// + /// The chain to append to. + /// Item 13. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T13 item13 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size; + var newSize = originalSize + item13Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + // Append the last structure + item13.StructureType(); + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + } + + /// + /// Creates a new with 15 items, by appending to + /// the end of this chain. + /// + /// Item 14. + /// Type of Item 14 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T14 item14 = default) + where T14: struct, IExtendsChain + { + return new ManagedChain(this, item14); + } + /// public void Dispose() { @@ -4203,6 +5058,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -4556,7 +5412,7 @@ public T14 Item14 } /// - /// Creates a new with 3 items. + /// Creates a new with 15 items. /// /// The head of the chain. /// Item 1. @@ -4667,6 +5523,101 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; } + /// + /// Creates a new with 15 items. + /// + /// The chain to append to. + /// Item 14. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T14 item14 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + var item14Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size; + var newSize = originalSize + item14Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + // Append the last structure + item14.StructureType(); + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + } + + /// + /// Creates a new with 16 items, by appending to + /// the end of this chain. + /// + /// Item 15. + /// Type of Item 15 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T15 item15 = default) + where T15: struct, IExtendsChain + { + return new ManagedChain(this, item15); + } + /// public void Dispose() { @@ -4708,6 +5659,7 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } + /// /// A safely manages the pointers of a managed structure chain. /// @@ -5084,7 +6036,7 @@ public T15 Item15 } /// - /// Creates a new with 3 items. + /// Creates a new with 16 items. /// /// The head of the chain. /// Item 1. @@ -5202,6 +6154,90 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; } + /// + /// Creates a new with 16 items. + /// + /// The chain to append to. + /// Item 15. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T15 item15 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + var item14Size = Marshal.SizeOf(); + var item15Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size; + var newSize = originalSize + item15Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + + _item15Ptr = _item14Ptr + item14Size; + // Append the last structure + item15.StructureType(); + Marshal.StructureToPtr(item15, _item15Ptr, false); + ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; + } + /// public void Dispose() { diff --git a/PrototypeStructChaining/ManagedChain.tt b/PrototypeStructChaining/ManagedChain.tt index ea244293d7..89df1c60b2 100644 --- a/PrototypeStructChaining/ManagedChain.tt +++ b/PrototypeStructChaining/ManagedChain.tt @@ -126,12 +126,12 @@ public static class ManagedChain } // for (var 2 = 1; i <= maximumItems; i++) { #> } - <# for (var i = 2; i <= maximumItems; i++) { var tList = typeList(i); #> + /// /// A safely manages the pointers of a managed structure chain. /// @@ -191,7 +191,7 @@ public unsafe class ManagedChain<<#= tList #>> : IDisposable #> /// - /// Creates a new with 3 items. + /// Creates a new with <#= i #> items. /// <#= parameterDocs(i, " /// ") #> public ManagedChain(<#= paramList(i) #>) @@ -231,6 +231,90 @@ public unsafe class ManagedChain<<#= tList #>> : IDisposable } // for (int j = 1; j < i; j++) { #> } +<# + if (i > 2) + { +#> + + /// + /// Creates a new with <#= i #> items. + /// + /// The chain to append to. + /// Item <#= i - 1 #>. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain<<#= typeList(i - 1) #>> previous, T<#= i - 1 #> item<#= i - 1 #> = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); +<# + for (var j = 1; j < i; j++) + { +#> + var item<#= j #>Size = Marshal.SizeOf>(); +<# + } // for (int j = 1; j < i; j++) { +#> + + var originalSize = headSize<# + for (var j = 1; j < i - 1; j++) + { +#> + item<#= j #>Size<# + } // for (int j = 1; j < i; j++) { +#>; + var newSize = originalSize + item<#= i - 1 #>Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); +<# + for (var j = 1; j < i; j++) + { + var prevItem = j > 1 + ? $"item{j - 1}" + : "head"; +#> + + _item<#= j #>Ptr = _<#= prevItem #>Ptr + <#= prevItem #>Size; +<# + if (j == i - 1) + {#> + // Append the last structure + item<#= j #>.StructureType(); + Marshal.StructureToPtr(item<#= j #>, _item<#= j #>Ptr, false); +<# + } // if (j == i - 1) + #> + ((Chain*) _<#= prevItem #>Ptr)->PNext = (Chain*) _item<#= j #>Ptr; +<# + } // for (int j = 1; j < i; j++) { +#> + } +<# + } //if (i > 2) + + if (i < maximumItems) + { +#> + + /// + /// Creates a new with <#= i + 1 #> items, by appending to + /// the end of this chain. + /// + /// Item <#= i #>. + /// Type of Item <#= i #> + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain<<#= tList #>, T<#= i #>> Append>(T<#= i #> item<#= i #> = default) + where T<#= i #>: struct, IExtendsChain + { + return new ManagedChain<<#= tList #>, T<#= i #>>(this, item<#= i #>); + } +<# + } // if (i < maximumItems) +#> /// public void Dispose() @@ -244,8 +328,8 @@ public unsafe class ManagedChain<<#= tList #>> : IDisposable for (var j = 1; j < i; j++) { #> - var item<#=j#>Ptr = Interlocked.Exchange(ref _item<#=j#>Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item<#=j#>Ptr); + var item<#= j #>Ptr = Interlocked.Exchange(ref _item<#= j #>Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item<#= j #>Ptr); <# } // for (int j = 1; j < i; j++) { #> diff --git a/Readme.md b/Readme.md index a2e8f5b431..5efa2bc43f 100644 --- a/Readme.md +++ b/Readme.md @@ -248,4 +248,19 @@ Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1 **Note** When we update any item in the chain it overwrites the existing memory, so the ptrs remain fixed. It also ensures the PNext value is maintained. -You can also use the `ManagedChain.Create(...)` static methods to create `ManagedChain`s. \ No newline at end of file +You can also use the `ManagedChain.Create(...)` static methods to create `ManagedChain`s. + +Finally, you can call append on a `ManagedChain` to create a new, larger, `ManagedChain` with a new item appended to the +end, e.g: + +```csharp +using var chain = new ManagedChain( + item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true}); + +// The new chain, will efficiently copy the old chain and append a new structure to the end +using var newChain = chain.Append(); +// You will usualy wish to dispose the old chain here, the two chains are now independent of each other. + +// Check the flag from the first chain is still set in the new chain. +Assert.True(newChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); +``` \ No newline at end of file From ea96e2a060d74861a2799f15e63a48a26e1965b0 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Fri, 5 Nov 2021 23:38:16 +0000 Subject: [PATCH 13/34] feat: Loading of unmanaged chains `ManagedChain` now has a constructor that will load an unmanaged chain allowing it to be safely stored on the heap. --- .../TestManagedChains.cs | 79 +- .../{ManagedChain.cs => ManagedChain.gen.cs} | 3776 ++++++++++++++++- .../{ManagedChain.tt => ManagedChain.gen.tt} | 71 +- .../PrototypeStructChaining.csproj | 33 +- Readme.md | 80 +- 5 files changed, 3898 insertions(+), 141 deletions(-) rename PrototypeStructChaining/{ManagedChain.cs => ManagedChain.gen.cs} (61%) rename PrototypeStructChaining/{ManagedChain.tt => ManagedChain.gen.tt} (80%) diff --git a/PrototypeStructChaining.Test/TestManagedChains.cs b/PrototypeStructChaining.Test/TestManagedChains.cs index e2dca905b8..6bbf0eb889 100644 --- a/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/PrototypeStructChaining.Test/TestManagedChains.cs @@ -101,7 +101,7 @@ public unsafe void TestManagedChainReplaceMiddle() // As is the SType Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); } - + [Fact] public unsafe void TestManagedChainAppend() { @@ -115,12 +115,12 @@ public unsafe void TestManagedChainAppend() // Ensure pointers set correctly Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); Assert.Equal((nint) 0, (nint) chain.Item1.PNext); - + // Check flag set Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); using var newChain = chain.Append(); - + // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, newChain.Head.SType); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, newChain.Item1.SType); @@ -130,12 +130,81 @@ public unsafe void TestManagedChainAppend() Assert.Equal((nint) newChain.Item1Ptr, (nint) newChain.Head.PNext); Assert.Equal((nint) newChain.Item2Ptr, (nint) newChain.Item1.PNext); Assert.Equal((nint) 0, (nint) newChain.Item2.PNext); - + // Check flag still set Assert.True(newChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); - + // Check we have new copies Assert.NotEqual((nint) chain.HeadPtr, (nint) newChain.HeadPtr); Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); } + + [Fact] + public unsafe void TestManagedChainLoad() + { + // Load an unmanaged chain + var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + { + ShaderInputAttachmentArrayDynamicIndexing = true + }; + PhysicalDeviceFeatures2 + .Chain(out var unmanagedChain) + .SetNext(ref indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + + // Loads a new managed chain from an unmanaged chain + using var managedChain = + new ManagedChain(unmanagedChain, out var errors); + + // Check we had no loading errors + Assert.Equal("", errors); + + // Check the flag still set + Assert.True(managedChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, managedChain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, managedChain.Item1.SType); + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, managedChain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) managedChain.Item1Ptr, (nint) managedChain.Head.PNext); + Assert.Equal((nint) managedChain.Item2Ptr, (nint) managedChain.Item1.PNext); + Assert.Equal((nint) 0, (nint) managedChain.Item2.PNext); + } + + [Fact] + public unsafe void TestManagedChainLoadWithError() + { + var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + { + ShaderInputAttachmentArrayDynamicIndexing = true + }; + // Load an unmanaged chain + DeviceCreateInfo + .Chain(out var unmanagedChain) + .AddNext(out PhysicalDeviceFeatures2 features2) + .SetNext(ref indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + + // Loads a new managed chain from an unmanaged chain + using var managedChain = + new ManagedChain< + DeviceCreateInfo, + // Note we are supplied a PhysicalDeviceFeatures2 here from the unmanaged chain + PhysicalDeviceAccelerationStructureFeaturesKHR, + PhysicalDeviceDescriptorIndexingFeatures, + PhysicalDeviceAccelerationStructureFeaturesKHR, + // Note that the unmanaged chain did not supply a 5th entry + PhysicalDeviceFeatures2>(unmanagedChain, out var errors); + + // Check for errors + Assert.Equal( + @"The unmanaged chain has a structure type PhysicalDeviceFeatures2Khr at position 2; expected PhysicalDeviceAccelerationStructureFeaturesKhr +The unmanaged chain was length 4, expected length 5", errors); + + // Despite the errors indexing features was at the right location so was loaded + Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); + } } \ No newline at end of file diff --git a/PrototypeStructChaining/ManagedChain.cs b/PrototypeStructChaining/ManagedChain.gen.cs similarity index 61% rename from PrototypeStructChaining/ManagedChain.cs rename to PrototypeStructChaining/ManagedChain.gen.cs index 26c14b2aad..0a58ef2b0b 100644 --- a/PrototypeStructChaining/ManagedChain.cs +++ b/PrototypeStructChaining/ManagedChain.gen.cs @@ -1,5 +1,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; namespace Silk.Net.Vulkan; @@ -20,7 +21,7 @@ public static ManagedChain Create(TChain head = default, where TChain : struct, IChainStart where T1 : struct, IExtendsChain { - return new(head, item1); + return new ManagedChain(head, item1); } /// @@ -33,12 +34,13 @@ public static ManagedChain Create(TChain head = default, /// Type of Item 1. /// Type of Item 2. /// A new with 3 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default) + public static ManagedChain Create(TChain head = default, T1 item1 = default, + T2 item2 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain { - return new(head, item1, item2); + return new ManagedChain(head, item1, item2); } /// @@ -53,13 +55,14 @@ public static ManagedChain Create(TChain head = /// Type of Item 2. /// Type of Item 3. /// A new with 4 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) + public static ManagedChain Create(TChain head = default, T1 item1 = default, + T2 item2 = default, T3 item3 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain { - return new(head, item1, item2, item3); + return new ManagedChain(head, item1, item2, item3); } /// @@ -76,14 +79,15 @@ public static ManagedChain Create(TChain /// Type of Item 3. /// Type of Item 4. /// A new with 5 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) + public static ManagedChain Create(TChain head = default, + T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain where T4 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4); + return new ManagedChain(head, item1, item2, item3, item4); } /// @@ -102,7 +106,8 @@ public static ManagedChain CreateType of Item 4. /// Type of Item 5. /// A new with 6 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + public static ManagedChain Create(TChain head = default, + T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -110,7 +115,7 @@ public static ManagedChain Create where T5 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5); + return new ManagedChain(head, item1, item2, item3, item4, item5); } /// @@ -131,7 +136,9 @@ public static ManagedChain CreateType of Item 5. /// Type of Item 6. /// A new with 7 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + public static ManagedChain Create( + TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, + T5 item5 = default, T6 item6 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -140,7 +147,7 @@ public static ManagedChain Create where T6 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6); + return new ManagedChain(head, item1, item2, item3, item4, item5, item6); } /// @@ -163,7 +170,9 @@ public static ManagedChain CreateType of Item 6. /// Type of Item 7. /// A new with 8 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) + public static ManagedChain Create( + TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, + T5 item5 = default, T6 item6 = default, T7 item7 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -173,7 +182,8 @@ public static ManagedChain Create where T7 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6, item7); + return new ManagedChain(head, item1, item2, item3, item4, item5, item6, + item7); } /// @@ -198,7 +208,9 @@ public static ManagedChain CreateType of Item 7. /// Type of Item 8. /// A new with 9 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + public static ManagedChain Create( + TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, + T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -209,7 +221,8 @@ public static ManagedChain Create where T8 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8); + return new ManagedChain(head, item1, item2, item3, item4, item5, item6, + item7, item8); } /// @@ -236,7 +249,10 @@ public static ManagedChain CreateType of Item 8. /// Type of Item 9. /// A new with 10 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + public static ManagedChain + Create(TChain head = default, T1 item1 = default, + T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, + T7 item7 = default, T8 item8 = default, T9 item9 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -248,7 +264,8 @@ public static ManagedChain Create where T9 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9); + return new ManagedChain(head, item1, item2, item3, item4, item5, + item6, item7, item8, item9); } /// @@ -277,7 +294,10 @@ public static ManagedChain CreateType of Item 9. /// Type of Item 10. /// A new with 11 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) + public static ManagedChain + Create(TChain head = default, T1 item1 = default, + T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, + T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -290,7 +310,8 @@ public static ManagedChain Crea where T9 : struct, IExtendsChain where T10 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10); + return new ManagedChain(head, item1, item2, item3, item4, + item5, item6, item7, item8, item9, item10); } /// @@ -321,7 +342,10 @@ public static ManagedChain Crea /// Type of Item 10. /// Type of Item 11. /// A new with 12 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + public static ManagedChain + Create(TChain head = default, T1 item1 = default, + T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, + T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -335,7 +359,8 @@ public static ManagedChain where T10 : struct, IExtendsChain where T11 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11); + return new ManagedChain(head, item1, item2, item3, item4, + item5, item6, item7, item8, item9, item10, item11); } /// @@ -368,7 +393,11 @@ public static ManagedChain /// Type of Item 11. /// Type of Item 12. /// A new with 13 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + public static ManagedChain + Create(TChain head = default, T1 item1 = default, + T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, + T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, + T12 item12 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -383,7 +412,8 @@ public static ManagedChain where T12 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12); + return new ManagedChain(head, item1, item2, item3, + item4, item5, item6, item7, item8, item9, item10, item11, item12); } /// @@ -418,7 +448,11 @@ public static ManagedChainType of Item 12. /// Type of Item 13. /// A new with 14 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + public static ManagedChain + Create(TChain head = default, + T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, + T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, + T11 item11 = default, T12 item12 = default, T13 item13 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -434,7 +468,8 @@ public static ManagedChain where T13 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); + return new ManagedChain(head, item1, item2, + item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); } /// @@ -471,7 +506,11 @@ public static ManagedChainType of Item 13. /// Type of Item 14. /// A new with 15 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + public static ManagedChain + Create(TChain head = default, + T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, + T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, + T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -488,7 +527,8 @@ public static ManagedChain where T14 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); + return new ManagedChain(head, item1, item2, + item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); } /// @@ -527,7 +567,12 @@ public static ManagedChainType of Item 14. /// Type of Item 15. /// A new with 16 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) + public static ManagedChain + Create(TChain head = default, + T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, + T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, + T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, + T15 item15 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -545,9 +590,9 @@ public static ManagedChain where T15 : struct, IExtendsChain { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); + return new ManagedChain(head, item1, + item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); } - } /// @@ -624,6 +669,53 @@ public ManagedChain(TChain head = default, T1 item1 = default) ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; } + /// + /// Creates a new with 2 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + } + /// /// Creates a new with 3 items, by appending to /// the end of this chain. @@ -634,7 +726,7 @@ public ManagedChain(TChain head = default, T1 item1 = default) /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T2 item2 = default) - where T2: struct, IExtendsChain + where T2 : struct, IExtendsChain { return new ManagedChain(this, item2); } @@ -709,6 +801,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -759,6 +852,78 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; } + /// + /// Creates a new with 3 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 3"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 3"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + } + /// /// Creates a new with 3 items. /// @@ -779,7 +944,7 @@ public ManagedChain(ManagedChain previous, T2 item2 = default) _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -801,7 +966,7 @@ public ManagedChain(ManagedChain previous, T2 item2 = default) /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T3 item3 = default) - where T3: struct, IExtendsChain + where T3 : struct, IExtendsChain { return new ManagedChain(this, item3); } @@ -880,6 +1045,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -901,6 +1067,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -958,6 +1125,103 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; } + /// + /// Creates a new with 4 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 4"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 4"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 4"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + } + /// /// Creates a new with 4 items. /// @@ -979,7 +1243,7 @@ public ManagedChain(ManagedChain previous, T3 item3 = default) _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -1004,7 +1268,7 @@ public ManagedChain(ManagedChain previous, T3 item3 = default) /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T4 item4 = default) - where T4: struct, IExtendsChain + where T4 : struct, IExtendsChain { return new ManagedChain(this, item4); } @@ -1087,6 +1351,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -1108,6 +1373,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -1129,6 +1395,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -1159,7 +1426,8 @@ public T4 Item4 /// Item 2. /// Item 3. /// Item 4. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -1193,6 +1461,128 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; } + /// + /// Creates a new with 5 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 5"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 5"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 5"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 5"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + } + /// /// Creates a new with 5 items. /// @@ -1215,7 +1605,7 @@ public ManagedChain(ManagedChain previous, T4 item4 = defaul _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -1243,7 +1633,7 @@ public ManagedChain(ManagedChain previous, T4 item4 = defaul /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T5 item5 = default) - where T5: struct, IExtendsChain + where T5 : struct, IExtendsChain { return new ManagedChain(this, item5); } @@ -1330,6 +1720,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -1351,6 +1742,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -1372,6 +1764,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -1393,6 +1786,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -1424,7 +1818,8 @@ public T5 Item5 /// Item 3. /// Item 4. /// Item 5. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -1464,6 +1859,153 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; } + /// + /// Creates a new with 6 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 6"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 6"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 6"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 6"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 6"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + } + /// /// Creates a new with 6 items. /// @@ -1487,7 +2029,7 @@ public ManagedChain(ManagedChain previous, T5 item5 = de _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -1518,7 +2060,7 @@ public ManagedChain(ManagedChain previous, T5 item5 = de /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T6 item6 = default) - where T6: struct, IExtendsChain + where T6 : struct, IExtendsChain { return new ManagedChain(this, item6); } @@ -1609,6 +2151,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -1630,6 +2173,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -1651,6 +2195,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -1672,6 +2217,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -1693,6 +2239,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -1725,7 +2272,8 @@ public T6 Item6 /// Item 4. /// Item 5. /// Item 6. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -1736,7 +2284,8 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item5Size = Marshal.SizeOf(); var item6Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); + _headPtr = Marshal.AllocHGlobal( + headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -1771,6 +2320,179 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; } + /// + /// Creates a new with 7 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 7"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 7"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 7"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 7"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 7"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 7"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + + var item6Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal( + headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + } + /// /// Creates a new with 7 items. /// @@ -1795,7 +2517,7 @@ public ManagedChain(ManagedChain previous, T6 item6 _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -1829,7 +2551,7 @@ public ManagedChain(ManagedChain previous, T6 item6 /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T7 item7 = default) - where T7: struct, IExtendsChain + where T7 : struct, IExtendsChain { return new ManagedChain(this, item7); } @@ -1924,6 +2646,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -1945,6 +2668,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -1966,6 +2690,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -1987,6 +2712,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -2008,6 +2734,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -2029,6 +2756,7 @@ public T6 Item6 ((Chain*) _item6Ptr)->PNext = nextPtr; } } + private IntPtr _item7Ptr; /// @@ -2062,7 +2790,8 @@ public T7 Item7 /// Item 5. /// Item 6. /// Item 7. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -2074,7 +2803,8 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item6Size = Marshal.SizeOf(); var item7Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -2115,7 +2845,205 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul } /// - /// Creates a new with 8 items. + /// Creates a new with 8 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 8"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 8"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 8"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 8"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 8"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 8"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 8"); + else + { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item7 = Unsafe.AsRef(currentPtr); + } + + var item7Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + } + + /// + /// Creates a new with 8 items. /// /// The chain to append to. /// Item 7. @@ -2139,7 +3067,7 @@ public ManagedChain(ManagedChain previous, T7 it _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -2176,7 +3104,7 @@ public ManagedChain(ManagedChain previous, T7 it /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T8 item8 = default) - where T8: struct, IExtendsChain + where T8 : struct, IExtendsChain { return new ManagedChain(this, item8); } @@ -2275,6 +3203,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -2296,6 +3225,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -2317,6 +3247,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -2338,6 +3269,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -2359,6 +3291,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -2380,6 +3313,7 @@ public T6 Item6 ((Chain*) _item6Ptr)->PNext = nextPtr; } } + private IntPtr _item7Ptr; /// @@ -2401,6 +3335,7 @@ public T7 Item7 ((Chain*) _item7Ptr)->PNext = nextPtr; } } + private IntPtr _item8Ptr; /// @@ -2435,7 +3370,8 @@ public T8 Item8 /// Item 6. /// Item 7. /// Item 8. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -2448,7 +3384,8 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item7Size = Marshal.SizeOf(); var item8Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -2493,6 +3430,229 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; } + /// + /// Creates a new with 9 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 9"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 9"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 9"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 9"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 9"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 9"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 9"); + else + { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item7 = Unsafe.AsRef(currentPtr); + } + + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 9"); + else + { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item8 = Unsafe.AsRef(currentPtr); + } + + var item8Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + } + /// /// Creates a new with 9 items. /// @@ -2519,7 +3679,7 @@ public ManagedChain(ManagedChain previous, T _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -2559,7 +3719,7 @@ public ManagedChain(ManagedChain previous, T /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T9 item9 = default) - where T9: struct, IExtendsChain + where T9 : struct, IExtendsChain { return new ManagedChain(this, item9); } @@ -2662,6 +3822,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -2683,6 +3844,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -2704,6 +3866,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -2725,6 +3888,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -2746,6 +3910,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -2767,6 +3932,7 @@ public T6 Item6 ((Chain*) _item6Ptr)->PNext = nextPtr; } } + private IntPtr _item7Ptr; /// @@ -2788,6 +3954,7 @@ public T7 Item7 ((Chain*) _item7Ptr)->PNext = nextPtr; } } + private IntPtr _item8Ptr; /// @@ -2809,6 +3976,7 @@ public T8 Item8 ((Chain*) _item8Ptr)->PNext = nextPtr; } } + private IntPtr _item9Ptr; /// @@ -2844,7 +4012,9 @@ public T9 Item9 /// Item 7. /// Item 8. /// Item 9. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, + T9 item9 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -2858,7 +4028,8 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item8Size = Marshal.SizeOf(); var item9Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -2908,6 +4079,254 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; } + /// + /// Creates a new with 10 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 10"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 10"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 10"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 10"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 10"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 10"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 10"); + else + { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item7 = Unsafe.AsRef(currentPtr); + } + + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 10"); + else + { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item8 = Unsafe.AsRef(currentPtr); + } + + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 10"); + else + { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item9 = Unsafe.AsRef(currentPtr); + } + + var item9Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + } + /// /// Creates a new with 10 items. /// @@ -2930,12 +4349,13 @@ public ManagedChain(ManagedChain previou var item8Size = Marshal.SizeOf(); var item9Size = Marshal.SizeOf(); - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size; + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + + item7Size + item8Size; var newSize = originalSize + item9Size; _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -2978,7 +4398,7 @@ public ManagedChain(ManagedChain previou /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T10 item10 = default) - where T10: struct, IExtendsChain + where T10 : struct, IExtendsChain { return new ManagedChain(this, item10); } @@ -3085,6 +4505,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -3106,6 +4527,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -3127,6 +4549,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -3148,6 +4571,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -3169,6 +4593,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -3190,6 +4615,7 @@ public T6 Item6 ((Chain*) _item6Ptr)->PNext = nextPtr; } } + private IntPtr _item7Ptr; /// @@ -3211,6 +4637,7 @@ public T7 Item7 ((Chain*) _item7Ptr)->PNext = nextPtr; } } + private IntPtr _item8Ptr; /// @@ -3232,6 +4659,7 @@ public T8 Item8 ((Chain*) _item8Ptr)->PNext = nextPtr; } } + private IntPtr _item9Ptr; /// @@ -3253,6 +4681,7 @@ public T9 Item9 ((Chain*) _item9Ptr)->PNext = nextPtr; } } + private IntPtr _item10Ptr; /// @@ -3289,7 +4718,9 @@ public T10 Item10 /// Item 8. /// Item 9. /// Item 10. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, + T9 item9 = default, T10 item10 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -3304,7 +4735,8 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item9Size = Marshal.SizeOf(); var item10Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -3360,18 +4792,291 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul } /// - /// Creates a new with 11 items. + /// Creates a new with 11 items from an existing unmanaged chain. /// - /// The chain to append to. - /// Item 10. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T10 item10 = default) + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) { - // Calculate memory requirements + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 11"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 11"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 11"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 11"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 11"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 11"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 11"); + else + { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item7 = Unsafe.AsRef(currentPtr); + } + + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 11"); + else + { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item8 = Unsafe.AsRef(currentPtr); + } + + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 11"); + else + { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item9 = Unsafe.AsRef(currentPtr); + } + + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 11"); + else + { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item10 = Unsafe.AsRef(currentPtr); + } + + var item10Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + } + + /// + /// Creates a new with 11 items. + /// + /// The chain to append to. + /// Item 10. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T10 item10 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); var item2Size = Marshal.SizeOf(); var item3Size = Marshal.SizeOf(); var item4Size = Marshal.SizeOf(); @@ -3382,12 +5087,13 @@ public ManagedChain(ManagedChain pre var item9Size = Marshal.SizeOf(); var item10Size = Marshal.SizeOf(); - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size; + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + + item7Size + item8Size + item9Size; var newSize = originalSize + item10Size; _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -3433,7 +5139,7 @@ public ManagedChain(ManagedChain pre /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T11 item11 = default) - where T11: struct, IExtendsChain + where T11 : struct, IExtendsChain { return new ManagedChain(this, item11); } @@ -3544,6 +5250,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -3565,6 +5272,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -3586,6 +5294,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -3607,6 +5316,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -3628,6 +5338,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -3649,6 +5360,7 @@ public T6 Item6 ((Chain*) _item6Ptr)->PNext = nextPtr; } } + private IntPtr _item7Ptr; /// @@ -3670,6 +5382,7 @@ public T7 Item7 ((Chain*) _item7Ptr)->PNext = nextPtr; } } + private IntPtr _item8Ptr; /// @@ -3691,6 +5404,7 @@ public T8 Item8 ((Chain*) _item8Ptr)->PNext = nextPtr; } } + private IntPtr _item9Ptr; /// @@ -3712,6 +5426,7 @@ public T9 Item9 ((Chain*) _item9Ptr)->PNext = nextPtr; } } + private IntPtr _item10Ptr; /// @@ -3733,6 +5448,7 @@ public T10 Item10 ((Chain*) _item10Ptr)->PNext = nextPtr; } } + private IntPtr _item11Ptr; /// @@ -3770,7 +5486,9 @@ public T11 Item11 /// Item 9. /// Item 10. /// Item 11. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, + T9 item9 = default, T10 item10 = default, T11 item11 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -3786,7 +5504,8 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item10Size = Marshal.SizeOf(); var item11Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -3846,6 +5565,304 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; } + /// + /// Creates a new with 12 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 12"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 12"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 12"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 12"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 12"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 12"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 12"); + else + { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item7 = Unsafe.AsRef(currentPtr); + } + + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 12"); + else + { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item8 = Unsafe.AsRef(currentPtr); + } + + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 12"); + else + { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item9 = Unsafe.AsRef(currentPtr); + } + + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 12"); + else + { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item10 = Unsafe.AsRef(currentPtr); + } + + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 12"); + else + { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item11 = Unsafe.AsRef(currentPtr); + } + + var item11Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + } + /// /// Creates a new with 12 items. /// @@ -3870,12 +5887,13 @@ public ManagedChain(ManagedChain(); var item11Size = Marshal.SizeOf(); - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size; + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + + item7Size + item8Size + item9Size + item10Size; var newSize = originalSize + item11Size; _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -3924,7 +5942,7 @@ public ManagedChain(ManagedChain public ManagedChain Append(T12 item12 = default) - where T12: struct, IExtendsChain + where T12 : struct, IExtendsChain { return new ManagedChain(this, item12); } @@ -4039,6 +6057,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -4060,6 +6079,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -4081,6 +6101,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -4102,6 +6123,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -4123,6 +6145,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -4144,6 +6167,7 @@ public T6 Item6 ((Chain*) _item6Ptr)->PNext = nextPtr; } } + private IntPtr _item7Ptr; /// @@ -4165,6 +6189,7 @@ public T7 Item7 ((Chain*) _item7Ptr)->PNext = nextPtr; } } + private IntPtr _item8Ptr; /// @@ -4186,6 +6211,7 @@ public T8 Item8 ((Chain*) _item8Ptr)->PNext = nextPtr; } } + private IntPtr _item9Ptr; /// @@ -4207,6 +6233,7 @@ public T9 Item9 ((Chain*) _item9Ptr)->PNext = nextPtr; } } + private IntPtr _item10Ptr; /// @@ -4228,6 +6255,7 @@ public T10 Item10 ((Chain*) _item10Ptr)->PNext = nextPtr; } } + private IntPtr _item11Ptr; /// @@ -4249,6 +6277,7 @@ public T11 Item11 ((Chain*) _item11Ptr)->PNext = nextPtr; } } + private IntPtr _item12Ptr; /// @@ -4287,7 +6316,9 @@ public T12 Item12 /// Item 10. /// Item 11. /// Item 12. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, + T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -4304,7 +6335,9 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item11Size = Marshal.SizeOf(); var item12Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + + item12Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -4370,36 +6403,362 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul } /// - /// Creates a new with 13 items. + /// Creates a new with 13 items from an existing unmanaged chain. /// - /// The chain to append to. - /// Item 12. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T12 item12 = default) + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) { - // Calculate memory requirements + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 13"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 13"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 13"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 13"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 13"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 13"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 13"); + else + { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item7 = Unsafe.AsRef(currentPtr); + } + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 13"); + else + { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item8 = Unsafe.AsRef(currentPtr); + } + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 13"); + else + { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item9 = Unsafe.AsRef(currentPtr); + } + var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size; - var newSize = originalSize + item12Size; + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 13"); + else + { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item10 = Unsafe.AsRef(currentPtr); + } + + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 13"); + else + { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item11 = Unsafe.AsRef(currentPtr); + } + + var item11Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T12 item12 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 13"); + else + { + expectedStructureType = item12.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item12 = Unsafe.AsRef(currentPtr); + } + + var item12Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + + item12Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + } + + /// + /// Creates a new with 13 items. + /// + /// The chain to append to. + /// Item 12. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, + T12 item12 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + + item7Size + item8Size + item9Size + item10Size + item11Size; + var newSize = originalSize + item12Size; _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -4450,8 +6809,9 @@ public ManagedChain(ManagedChain /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain Append(T13 item13 = default) - where T13: struct, IExtendsChain + public ManagedChain Append( + T13 item13 = default) + where T13 : struct, IExtendsChain { return new ManagedChain(this, item13); } @@ -4570,6 +6930,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -4591,6 +6952,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -4612,6 +6974,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -4633,6 +6996,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -4654,6 +7018,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -4675,6 +7040,7 @@ public T6 Item6 ((Chain*) _item6Ptr)->PNext = nextPtr; } } + private IntPtr _item7Ptr; /// @@ -4696,6 +7062,7 @@ public T7 Item7 ((Chain*) _item7Ptr)->PNext = nextPtr; } } + private IntPtr _item8Ptr; /// @@ -4717,6 +7084,7 @@ public T8 Item8 ((Chain*) _item8Ptr)->PNext = nextPtr; } } + private IntPtr _item9Ptr; /// @@ -4738,6 +7106,7 @@ public T9 Item9 ((Chain*) _item9Ptr)->PNext = nextPtr; } } + private IntPtr _item10Ptr; /// @@ -4759,6 +7128,7 @@ public T10 Item10 ((Chain*) _item10Ptr)->PNext = nextPtr; } } + private IntPtr _item11Ptr; /// @@ -4780,6 +7150,7 @@ public T11 Item11 ((Chain*) _item11Ptr)->PNext = nextPtr; } } + private IntPtr _item12Ptr; /// @@ -4801,6 +7172,7 @@ public T12 Item12 ((Chain*) _item12Ptr)->PNext = nextPtr; } } + private IntPtr _item13Ptr; /// @@ -4840,7 +7212,9 @@ public T13 Item13 /// Item 11. /// Item 12. /// Item 13. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, + T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -4858,7 +7232,9 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item12Size = Marshal.SizeOf(); var item13Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + + item12Size + item13Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -4928,6 +7304,355 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; } + /// + /// Creates a new with 14 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 14"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 14"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 14"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 14"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 14"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 14"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 14"); + else + { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item7 = Unsafe.AsRef(currentPtr); + } + + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 14"); + else + { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item8 = Unsafe.AsRef(currentPtr); + } + + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 14"); + else + { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item9 = Unsafe.AsRef(currentPtr); + } + + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 14"); + else + { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item10 = Unsafe.AsRef(currentPtr); + } + + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 14"); + else + { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item11 = Unsafe.AsRef(currentPtr); + } + + var item11Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T12 item12 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 14"); + else + { + expectedStructureType = item12.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item12 = Unsafe.AsRef(currentPtr); + } + + var item12Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T13 item13 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 14"); + else + { + expectedStructureType = item13.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 14; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item13 = Unsafe.AsRef(currentPtr); + } + + var item13Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + + item12Size + item13Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + } + /// /// Creates a new with 14 items. /// @@ -4936,7 +7661,8 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// /// Do not forget to dispose the chain if you are no longer using it. /// - public ManagedChain(ManagedChain previous, T13 item13 = default) + public ManagedChain(ManagedChain previous, + T13 item13 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -4954,12 +7680,13 @@ public ManagedChain(ManagedChain(); var item13Size = Marshal.SizeOf(); - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size; + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size; var newSize = originalSize + item13Size; _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -5013,8 +7740,9 @@ public ManagedChain(ManagedChain /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain Append(T14 item14 = default) - where T14: struct, IExtendsChain + public ManagedChain Append( + T14 item14 = default) + where T14 : struct, IExtendsChain { return new ManagedChain(this, item14); } @@ -5137,6 +7865,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -5158,6 +7887,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -5179,6 +7909,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -5200,6 +7931,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -5221,6 +7953,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -5242,6 +7975,7 @@ public T6 Item6 ((Chain*) _item6Ptr)->PNext = nextPtr; } } + private IntPtr _item7Ptr; /// @@ -5263,6 +7997,7 @@ public T7 Item7 ((Chain*) _item7Ptr)->PNext = nextPtr; } } + private IntPtr _item8Ptr; /// @@ -5284,6 +8019,7 @@ public T8 Item8 ((Chain*) _item8Ptr)->PNext = nextPtr; } } + private IntPtr _item9Ptr; /// @@ -5305,6 +8041,7 @@ public T9 Item9 ((Chain*) _item9Ptr)->PNext = nextPtr; } } + private IntPtr _item10Ptr; /// @@ -5326,6 +8063,7 @@ public T10 Item10 ((Chain*) _item10Ptr)->PNext = nextPtr; } } + private IntPtr _item11Ptr; /// @@ -5347,6 +8085,7 @@ public T11 Item11 ((Chain*) _item11Ptr)->PNext = nextPtr; } } + private IntPtr _item12Ptr; /// @@ -5368,6 +8107,7 @@ public T12 Item12 ((Chain*) _item12Ptr)->PNext = nextPtr; } } + private IntPtr _item13Ptr; /// @@ -5389,6 +8129,7 @@ public T13 Item13 ((Chain*) _item13Ptr)->PNext = nextPtr; } } + private IntPtr _item14Ptr; /// @@ -5429,7 +8170,10 @@ public T14 Item14 /// Item 12. /// Item 13. /// Item 14. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, + T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, + T14 item14 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -5448,7 +8192,9 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item13Size = Marshal.SizeOf(); var item14Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + + item12Size + item13Size + item14Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -5523,6 +8269,380 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; } + /// + /// Creates a new with 15 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 15"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 15"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 15"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 15"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 15"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 15"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 15"); + else + { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item7 = Unsafe.AsRef(currentPtr); + } + + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 15"); + else + { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item8 = Unsafe.AsRef(currentPtr); + } + + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 15"); + else + { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item9 = Unsafe.AsRef(currentPtr); + } + + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 15"); + else + { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item10 = Unsafe.AsRef(currentPtr); + } + + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 15"); + else + { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item11 = Unsafe.AsRef(currentPtr); + } + + var item11Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T12 item12 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 15"); + else + { + expectedStructureType = item12.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item12 = Unsafe.AsRef(currentPtr); + } + + var item12Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T13 item13 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 15"); + else + { + expectedStructureType = item13.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 14; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item13 = Unsafe.AsRef(currentPtr); + } + + var item13Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T14 item14 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 15"); + else + { + expectedStructureType = item14.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 15; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item14 = Unsafe.AsRef(currentPtr); + } + + var item14Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + + item12Size + item13Size + item14Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + } + /// /// Creates a new with 15 items. /// @@ -5531,7 +8651,8 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// /// Do not forget to dispose the chain if you are no longer using it. /// - public ManagedChain(ManagedChain previous, T14 item14 = default) + public ManagedChain(ManagedChain previous, + T14 item14 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -5550,12 +8671,13 @@ public ManagedChain(ManagedChain(); var item14Size = Marshal.SizeOf(); - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size; + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size; var newSize = originalSize + item14Size; _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -5612,8 +8734,9 @@ public ManagedChain(ManagedChain /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain Append(T15 item15 = default) - where T15: struct, IExtendsChain + public ManagedChain Append( + T15 item15 = default) + where T15 : struct, IExtendsChain { return new ManagedChain(this, item15); } @@ -5740,6 +8863,7 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// @@ -5761,6 +8885,7 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } + private IntPtr _item3Ptr; /// @@ -5782,6 +8907,7 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// @@ -5803,6 +8929,7 @@ public T4 Item4 ((Chain*) _item4Ptr)->PNext = nextPtr; } } + private IntPtr _item5Ptr; /// @@ -5824,6 +8951,7 @@ public T5 Item5 ((Chain*) _item5Ptr)->PNext = nextPtr; } } + private IntPtr _item6Ptr; /// @@ -5845,6 +8973,7 @@ public T6 Item6 ((Chain*) _item6Ptr)->PNext = nextPtr; } } + private IntPtr _item7Ptr; /// @@ -5866,6 +8995,7 @@ public T7 Item7 ((Chain*) _item7Ptr)->PNext = nextPtr; } } + private IntPtr _item8Ptr; /// @@ -5887,6 +9017,7 @@ public T8 Item8 ((Chain*) _item8Ptr)->PNext = nextPtr; } } + private IntPtr _item9Ptr; /// @@ -5908,6 +9039,7 @@ public T9 Item9 ((Chain*) _item9Ptr)->PNext = nextPtr; } } + private IntPtr _item10Ptr; /// @@ -5929,6 +9061,7 @@ public T10 Item10 ((Chain*) _item10Ptr)->PNext = nextPtr; } } + private IntPtr _item11Ptr; /// @@ -5950,6 +9083,7 @@ public T11 Item11 ((Chain*) _item11Ptr)->PNext = nextPtr; } } + private IntPtr _item12Ptr; /// @@ -5971,6 +9105,7 @@ public T12 Item12 ((Chain*) _item12Ptr)->PNext = nextPtr; } } + private IntPtr _item13Ptr; /// @@ -5992,6 +9127,7 @@ public T13 Item13 ((Chain*) _item13Ptr)->PNext = nextPtr; } } + private IntPtr _item14Ptr; /// @@ -6013,6 +9149,7 @@ public T14 Item14 ((Chain*) _item14Ptr)->PNext = nextPtr; } } + private IntPtr _item15Ptr; /// @@ -6054,7 +9191,10 @@ public T15 Item15 /// Item 13. /// Item 14. /// Item 15. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, + T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, + T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, + T14 item14 = default, T15 item15 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -6074,7 +9214,9 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item14Size = Marshal.SizeOf(); var item15Size = Marshal.SizeOf(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size + item15Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + + item12Size + item13Size + item14Size + item15Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -6154,6 +9296,405 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; } + /// + /// Creates a new with 16 items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + var errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 16"); + else + { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item1 = Unsafe.AsRef(currentPtr); + } + + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 16"); + else + { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item2 = Unsafe.AsRef(currentPtr); + } + + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 16"); + else + { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item3 = Unsafe.AsRef(currentPtr); + } + + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 16"); + else + { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item4 = Unsafe.AsRef(currentPtr); + } + + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 16"); + else + { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item5 = Unsafe.AsRef(currentPtr); + } + + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 16"); + else + { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item6 = Unsafe.AsRef(currentPtr); + } + + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 16"); + else + { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item7 = Unsafe.AsRef(currentPtr); + } + + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 16"); + else + { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item8 = Unsafe.AsRef(currentPtr); + } + + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 16"); + else + { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item9 = Unsafe.AsRef(currentPtr); + } + + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 16"); + else + { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item10 = Unsafe.AsRef(currentPtr); + } + + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 16"); + else + { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item11 = Unsafe.AsRef(currentPtr); + } + + var item11Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T12 item12 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 16"); + else + { + expectedStructureType = item12.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item12 = Unsafe.AsRef(currentPtr); + } + + var item12Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T13 item13 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 16"); + else + { + expectedStructureType = item13.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 14; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item13 = Unsafe.AsRef(currentPtr); + } + + var item13Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T14 item14 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 16"); + else + { + expectedStructureType = item14.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 15; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item14 = Unsafe.AsRef(currentPtr); + } + + var item14Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T15 item15 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 15, expected length 16"); + else + { + expectedStructureType = item15.StructureType(); + if (currentPtr->SType != expectedStructureType) + { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 16; expected ") + .Append(expectedStructureType) + .AppendLine(); + } + else + item15 = Unsafe.AsRef(currentPtr); + } + + var item15Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + + item12Size + item13Size + item14Size + item15Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + + _item15Ptr = _item14Ptr + item14Size; + Marshal.StructureToPtr(item15, _item15Ptr, false); + ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; + } + /// /// Creates a new with 16 items. /// @@ -6162,7 +9703,8 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// /// Do not forget to dispose the chain if you are no longer using it. /// - public ManagedChain(ManagedChain previous, T15 item15 = default) + public ManagedChain(ManagedChain previous, + T15 item15 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -6182,12 +9724,14 @@ public ManagedChain(ManagedChain(); var item15Size = Marshal.SizeOf(); - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size; + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + + item14Size; var newSize = originalSize + item15Size; _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -6280,4 +9824,4 @@ public void Dispose() // Free memory block Marshal.FreeHGlobal(headPtr); } -} +} \ No newline at end of file diff --git a/PrototypeStructChaining/ManagedChain.tt b/PrototypeStructChaining/ManagedChain.gen.tt similarity index 80% rename from PrototypeStructChaining/ManagedChain.tt rename to PrototypeStructChaining/ManagedChain.gen.tt index 89df1c60b2..cb91403f6c 100644 --- a/PrototypeStructChaining/ManagedChain.tt +++ b/PrototypeStructChaining/ManagedChain.gen.tt @@ -97,6 +97,7 @@ #> using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; namespace Silk.Net.Vulkan; @@ -229,6 +230,71 @@ public unsafe class ManagedChain<<#= tList #>> : IDisposable ((Chain*) _<#= prevItem #>Ptr)->PNext = (Chain*) _item<#= j #>Ptr; <# } // for (int j = 1; j < i; j++) { +#> + } + + /// + /// Creates a new with <#= i #> items from an existing unmanaged chain. + /// + /// The unmanaged chain to use as the basis of this chain. + /// Any errors loading the chain. + public ManagedChain(TChain chain, out string errors) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + +<# + for (var j = 1; j < i; j++) + { +#> + currentPtr = currentPtr->PNext; + T<#= j #> item<#= j #> = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length <#= j #>, expected length <#= i #>"); + else { + expectedStructureType = item<#= j #>.StructureType(); + if (currentPtr->SType != expectedStructureType) + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position <#= j + 1 #>; expected ") + .Append(expectedStructureType) + .AppendLine(); + else + item<#= j #> = Unsafe.AsRef>(currentPtr); + } + var item<#= j #>Size = Marshal.SizeOf>(); + +<# + } // for (int j = 1; j < i; j++) { +#> + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize<# + for (var j = 1; j < i; j++) + { +#> + item<#= j #>Size<# + } // for (int j = 1; j < i; j++) { +#>); + Marshal.StructureToPtr(head, _headPtr, false); +<# + for (var j = 1; j < i; j++) + { + var prevItem = j > 1 + ? $"item{j - 1}" + : "head"; +#> + + _item<#= j #>Ptr = _<#= prevItem #>Ptr + <#= prevItem #>Size; + Marshal.StructureToPtr(item<#= j #>, _item<#= j #>Ptr, false); + ((Chain*) _<#= prevItem #>Ptr)->PNext = (Chain*) _item<#= j #>Ptr; +<# + } // for (int j = 1; j < i; j++) { #> } <# @@ -279,13 +345,14 @@ public unsafe class ManagedChain<<#= tList #>> : IDisposable _item<#= j #>Ptr = _<#= prevItem #>Ptr + <#= prevItem #>Size; <# if (j == i - 1) - {#> + { +#> // Append the last structure item<#= j #>.StructureType(); Marshal.StructureToPtr(item<#= j #>, _item<#= j #>Ptr, false); <# } // if (j == i - 1) - #> +#> ((Chain*) _<#= prevItem #>Ptr)->PNext = (Chain*) _item<#= j #>Ptr; <# } // for (int j = 1; j < i; j++) { diff --git a/PrototypeStructChaining/PrototypeStructChaining.csproj b/PrototypeStructChaining/PrototypeStructChaining.csproj index 6de1a80a99..7feb76b14e 100644 --- a/PrototypeStructChaining/PrototypeStructChaining.csproj +++ b/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -10,28 +10,33 @@ - - - - - - - + + + + + + + - + TextTemplatingFileGenerator - ManagedChain.cs + ManagedChain.gen.cs - - True - True - ManagedChain.tt - + + True + True + ManagedChain.gen.tt + + + True + True + ManagedChain.gen.tt + diff --git a/Readme.md b/Readme.md index 5efa2bc43f..4f51bfb5ad 100644 --- a/Readme.md +++ b/Readme.md @@ -181,7 +181,9 @@ Sometimes it is desirable to keep the structures around on the heap. To facilita the `ManagedChain` types. Like `Tuple` et al, these support up to chain size 16. They should be disposed when finished with. -Example: +### Creation + +For example: ```csharp using var chain = new ManagedChain( @@ -263,4 +269,70 @@ using var newChain = chain.Append(unmanagedChain, out var errors); + +// Check we had no loading errors +Assert.Equal("", errors); + +// Check the flag still set +Assert.True(managedChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); +``` + +Notice that this special form of the constructor returns an output parameter `errors`. It does this to prevent any +possible confusion with the normal constructor which also can accept a single parameter of type `TChain` (which will +only load the head of the chain). Secondly, it also allows the constructor to indicate any failures that occurred whilst +loading from the unmanaged type, for example: + +```csharp +var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures +{ + ShaderInputAttachmentArrayDynamicIndexing = true +}; +// Load an unmanaged chain +DeviceCreateInfo + .Chain(out var unmanagedChain) + .AddNext(out PhysicalDeviceFeatures2 features2) + .SetNext(ref indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + +// Loads a new managed chain from an unmanaged chain +using var managedChain = + new ManagedChain< + DeviceCreateInfo, + // Note we are supplied a PhysicalDeviceFeatures2 here from the unmanaged chain + PhysicalDeviceAccelerationStructureFeaturesKHR, + PhysicalDeviceDescriptorIndexingFeatures, + PhysicalDeviceAccelerationStructureFeaturesKHR, + // Note that the unmanaged chain did not supply a 5th entry + PhysicalDeviceFeatures2>(unmanagedChain, out var errors); + +// Check for errors +Assert.Equal( +@"The unmanaged chain has a structure type PhysicalDeviceFeatures2Khr at position 2; expected PhysicalDeviceAccelerationStructureFeaturesKhr +The unmanaged chain was length 4, expected length 5", + errors); + +// Despite the errors indexing features was at the right location so was loaded +Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); ``` \ No newline at end of file From ec40730b7dbcd014289acc8bf62e2ecf920fce59 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sat, 6 Nov 2021 00:23:02 +0000 Subject: [PATCH 14/34] feat: Added `IReadOnlyList` support to `ManagedChain` --- .../TestManagedChains.cs | 26 + PrototypeStructChaining/ManagedChain.gen.cs | 8943 +---------------- PrototypeStructChaining/ManagedChain.gen.tt | 61 +- .../PrototypeStructChaining.csproj | 28 +- Readme.md | 29 +- 5 files changed, 278 insertions(+), 8809 deletions(-) diff --git a/PrototypeStructChaining.Test/TestManagedChains.cs b/PrototypeStructChaining.Test/TestManagedChains.cs index 6bbf0eb889..6708f88bad 100644 --- a/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/PrototypeStructChaining.Test/TestManagedChains.cs @@ -1,3 +1,5 @@ +using System; +using System.Linq; using Silk.Net.Vulkan; using Xunit; @@ -207,4 +209,28 @@ public unsafe void TestManagedChainLoadWithError() // Despite the errors indexing features was at the right location so was loaded Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); } + + [Fact] + public unsafe void TestReadOnlyList() + { + using var chain = new ManagedChain(); + + Assert.Equal(3, chain.Count); + + // Ensure all STypes set correctly using indexer + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain[0].StructureType()); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain[1].StructureType()); + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain[2].StructureType()); + + Assert.Throws(() => chain[3]); + + // Get array using IEnumerable implementation + IChainable[] structures = chain.ToArray(); + + // Check concrete types + Assert.IsType(structures[0]); + Assert.IsType(structures[1]); + Assert.IsType(structures[2]); + } } \ No newline at end of file diff --git a/PrototypeStructChaining/ManagedChain.gen.cs b/PrototypeStructChaining/ManagedChain.gen.cs index 0a58ef2b0b..6d3e16ebc9 100644 --- a/PrototypeStructChaining/ManagedChain.gen.cs +++ b/PrototypeStructChaining/ManagedChain.gen.cs @@ -1,3 +1,4 @@ +using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -7,8 +8,24 @@ namespace Silk.Net.Vulkan; /// /// Static class for creating Managed Chains. /// -public static class ManagedChain +public abstract class ManagedChain : IReadOnlyList, IDisposable { + /// + public abstract IEnumerator GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + public abstract int Count { get; } + + /// + public abstract IChainable this[int index] { get; } + + /// + public abstract void Dispose(); + /// /// Creates a new with 2 items. /// @@ -21,7 +38,7 @@ public static ManagedChain Create(TChain head = default, where TChain : struct, IChainStart where T1 : struct, IExtendsChain { - return new ManagedChain(head, item1); + return new(head, item1); } /// @@ -34,13 +51,12 @@ public static ManagedChain Create(TChain head = default, /// Type of Item 1. /// Type of Item 2. /// A new with 3 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, - T2 item2 = default) + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain { - return new ManagedChain(head, item1, item2); + return new(head, item1, item2); } /// @@ -55,14 +71,13 @@ public static ManagedChain Create(TChain head = /// Type of Item 2. /// Type of Item 3. /// A new with 4 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, - T2 item2 = default, T3 item3 = default) + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain { - return new ManagedChain(head, item1, item2, item3); + return new(head, item1, item2, item3); } /// @@ -79,520 +94,16 @@ public static ManagedChain Create(TChain /// Type of Item 3. /// Type of Item 4. /// A new with 5 items. - public static ManagedChain Create(TChain head = default, - T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, item3, item4); - } - - /// - /// Creates a new with 6 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// A new with 6 items. - public static ManagedChain Create(TChain head = default, - T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, item3, item4, item5); - } - - /// - /// Creates a new with 7 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// A new with 7 items. - public static ManagedChain Create( - TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, - T5 item5 = default, T6 item6 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, item3, item4, item5, item6); - } - - /// - /// Creates a new with 8 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// A new with 8 items. - public static ManagedChain Create( - TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, - T5 item5 = default, T6 item6 = default, T7 item7 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, item3, item4, item5, item6, - item7); - } - - /// - /// Creates a new with 9 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// A new with 9 items. - public static ManagedChain Create( - TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, - T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, item3, item4, item5, item6, - item7, item8); - } - - /// - /// Creates a new with 10 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// A new with 10 items. - public static ManagedChain - Create(TChain head = default, T1 item1 = default, - T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, - T7 item7 = default, T8 item8 = default, T9 item9 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, item3, item4, item5, - item6, item7, item8, item9); - } - - /// - /// Creates a new with 11 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// A new with 11 items. - public static ManagedChain - Create(TChain head = default, T1 item1 = default, - T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, - T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, item3, item4, - item5, item6, item7, item8, item9, item10); - } - - /// - /// Creates a new with 12 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// Type of Item 11. - /// A new with 12 items. - public static ManagedChain - Create(TChain head = default, T1 item1 = default, - T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, - T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, item3, item4, - item5, item6, item7, item8, item9, item10, item11); - } - - /// - /// Creates a new with 13 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// Type of Item 11. - /// Type of Item 12. - /// A new with 13 items. - public static ManagedChain - Create(TChain head = default, T1 item1 = default, - T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, - T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, - T12 item12 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, item3, - item4, item5, item6, item7, item8, item9, item10, item11, item12); - } - - /// - /// Creates a new with 14 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// Type of Item 11. - /// Type of Item 12. - /// Type of Item 13. - /// A new with 14 items. - public static ManagedChain - Create(TChain head = default, - T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, - T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, - T11 item11 = default, T12 item12 = default, T13 item13 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - { - return new ManagedChain(head, item1, item2, - item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); - } - - /// - /// Creates a new with 15 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - /// Item 14. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// Type of Item 11. - /// Type of Item 12. - /// Type of Item 13. - /// Type of Item 14. - /// A new with 15 items. - public static ManagedChain - Create(TChain head = default, - T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, - T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, - T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain { - return new ManagedChain(head, item1, item2, - item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); + return new(head, item1, item2, item3, item4); } - /// - /// Creates a new with 16 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - /// Item 14. - /// Item 15. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// Type of Item 11. - /// Type of Item 12. - /// Type of Item 13. - /// Type of Item 14. - /// Type of Item 15. - /// A new with 16 items. - public static ManagedChain - Create(TChain head = default, - T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, - T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, - T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, - T15 item15 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain - where T15 : struct, IExtendsChain - { - return new ManagedChain(head, item1, - item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); - } } /// @@ -600,7 +111,7 @@ public static ManagedChain /// The chain type /// Type of Item 1. -public unsafe class ManagedChain : IDisposable +public unsafe class ManagedChain : ManagedChain where TChain : struct, IChainStart where T1 : struct, IExtendsChain { @@ -681,27 +192,23 @@ public ManagedChain(TChain chain, out string errors) var headSize = Marshal.SizeOf(); var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); + StringBuilder errorBuilder = new StringBuilder(); currentPtr = currentPtr->PNext; T1 item1 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); - else - { + else { expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item1 = Unsafe.AsRef(currentPtr); } - var item1Size = Marshal.SizeOf(); @@ -726,13 +233,31 @@ public ManagedChain(TChain chain, out string errors) /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T2 item2 = default) - where T2 : struct, IExtendsChain + where T2: struct, IExtendsChain { return new ManagedChain(this, item2); } /// - public void Dispose() + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + } + + /// + public override int Count => 2; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + _ => throw new IndexOutOfRangeException() + }; + + /// + public override void Dispose() { var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); if (headPtr == IntPtr.Zero) return; @@ -753,7 +278,7 @@ public void Dispose() /// The chain type /// Type of Item 1. /// Type of Item 2. -public unsafe class ManagedChain : IDisposable +public unsafe class ManagedChain : ManagedChain where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -801,7 +326,6 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// @@ -864,48 +388,40 @@ public ManagedChain(TChain chain, out string errors) var headSize = Marshal.SizeOf(); var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); + StringBuilder errorBuilder = new StringBuilder(); currentPtr = currentPtr->PNext; T1 item1 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 3"); - else - { + else { expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item1 = Unsafe.AsRef(currentPtr); } - var item1Size = Marshal.SizeOf(); currentPtr = currentPtr->PNext; T2 item2 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 3"); - else - { + else { expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item2 = Unsafe.AsRef(currentPtr); } - var item2Size = Marshal.SizeOf(); @@ -944,7 +460,7 @@ public ManagedChain(ManagedChain previous, T2 item2 = default) _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -966,13 +482,33 @@ public ManagedChain(ManagedChain previous, T2 item2 = default) /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T3 item3 = default) - where T3 : struct, IExtendsChain + where T3: struct, IExtendsChain { return new ManagedChain(this, item3); } /// - public void Dispose() + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + } + + /// + public override int Count => 3; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + _ => throw new IndexOutOfRangeException() + }; + + /// + public override void Dispose() { var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); if (headPtr == IntPtr.Zero) return; @@ -996,7 +532,7 @@ public void Dispose() /// Type of Item 1. /// Type of Item 2. /// Type of Item 3. -public unsafe class ManagedChain : IDisposable +public unsafe class ManagedChain : ManagedChain where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -1045,7 +581,6 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// @@ -1067,7 +602,6 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// @@ -1137,69 +671,57 @@ public ManagedChain(TChain chain, out string errors) var headSize = Marshal.SizeOf(); var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); + StringBuilder errorBuilder = new StringBuilder(); currentPtr = currentPtr->PNext; T1 item1 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 4"); - else - { + else { expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item1 = Unsafe.AsRef(currentPtr); } - var item1Size = Marshal.SizeOf(); currentPtr = currentPtr->PNext; T2 item2 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 4"); - else - { + else { expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item2 = Unsafe.AsRef(currentPtr); } - var item2Size = Marshal.SizeOf(); currentPtr = currentPtr->PNext; T3 item3 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 4"); - else - { + else { expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item3 = Unsafe.AsRef(currentPtr); } - var item3Size = Marshal.SizeOf(); @@ -1243,7 +765,7 @@ public ManagedChain(ManagedChain previous, T3 item3 = default) _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -1268,13 +790,35 @@ public ManagedChain(ManagedChain previous, T3 item3 = default) /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T4 item4 = default) - where T4 : struct, IExtendsChain + where T4: struct, IExtendsChain { return new ManagedChain(this, item4); } /// - public void Dispose() + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + } + + /// + public override int Count => 4; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + _ => throw new IndexOutOfRangeException() + }; + + /// + public override void Dispose() { var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); if (headPtr == IntPtr.Zero) return; @@ -1301,7 +845,7 @@ public void Dispose() /// Type of Item 2. /// Type of Item 3. /// Type of Item 4. -public unsafe class ManagedChain : IDisposable +public unsafe class ManagedChain : ManagedChain where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -1351,7 +895,6 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// @@ -1373,7 +916,6 @@ public T2 Item2 ((Chain*) _item2Ptr)->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// @@ -1395,7 +937,6 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// @@ -1426,8 +967,7 @@ public T4 Item4 /// Item 2. /// Item 3. /// Item 4. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default) + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -1473,90 +1013,74 @@ public ManagedChain(TChain chain, out string errors) var headSize = Marshal.SizeOf(); var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); + StringBuilder errorBuilder = new StringBuilder(); currentPtr = currentPtr->PNext; T1 item1 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 5"); - else - { + else { expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item1 = Unsafe.AsRef(currentPtr); } - var item1Size = Marshal.SizeOf(); currentPtr = currentPtr->PNext; T2 item2 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 5"); - else - { + else { expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item2 = Unsafe.AsRef(currentPtr); } - var item2Size = Marshal.SizeOf(); currentPtr = currentPtr->PNext; T3 item3 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 5"); - else - { + else { expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item3 = Unsafe.AsRef(currentPtr); } - var item3Size = Marshal.SizeOf(); currentPtr = currentPtr->PNext; T4 item4 = default; if (currentPtr is null) errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 5"); - else - { + else { expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } - else + } else item4 = Unsafe.AsRef(currentPtr); } - var item4Size = Marshal.SizeOf(); @@ -1605,7 +1129,7 @@ public ManagedChain(ManagedChain previous, T4 item4 = defaul _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); _item1Ptr = _headPtr + headSize; ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; @@ -1623,23 +1147,32 @@ public ManagedChain(ManagedChain previous, T4 item4 = defaul ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; } - /// - /// Creates a new with 6 items, by appending to - /// the end of this chain. - /// - /// Item 5. - /// Type of Item 5 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T5 item5 = default) - where T5 : struct, IExtendsChain + /// + public override IEnumerator GetEnumerator() { - return new ManagedChain(this, item5); + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; } /// - public void Dispose() + public override int Count => 5; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + _ => throw new IndexOutOfRangeException() + }; + + /// + public override void Dispose() { var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); if (headPtr == IntPtr.Zero) return; @@ -1659,8169 +1192,3 @@ public void Dispose() Marshal.FreeHGlobal(headPtr); } } - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 6 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - } - - /// - /// Creates a new with 6 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 6"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 6"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 6"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 6"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 6"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - } - - /// - /// Creates a new with 6 items. - /// - /// The chain to append to. - /// Item 5. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T5 item5 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size; - var newSize = originalSize + item5Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - // Append the last structure - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - } - - /// - /// Creates a new with 7 items, by appending to - /// the end of this chain. - /// - /// Item 6. - /// Type of Item 6 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T6 item6 = default) - where T6 : struct, IExtendsChain - { - return new ManagedChain(this, item6); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 7 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal( - headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - } - - /// - /// Creates a new with 7 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 7"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 7"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 7"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 7"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 7"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 7"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal( - headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - } - - /// - /// Creates a new with 7 items. - /// - /// The chain to append to. - /// Item 6. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T6 item6 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size; - var newSize = originalSize + item6Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - // Append the last structure - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - } - - /// - /// Creates a new with 8 items, by appending to - /// the end of this chain. - /// - /// Item 7. - /// Type of Item 7 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T7 item7 = default) - where T7 : struct, IExtendsChain - { - return new ManagedChain(this, item7); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item7Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef((Chain*) _item7Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 8 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - } - - /// - /// Creates a new with 8 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 8"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 8"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 8"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 8"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 8"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 8"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T7 item7 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 8"); - else - { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item7 = Unsafe.AsRef(currentPtr); - } - - var item7Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - } - - /// - /// Creates a new with 8 items. - /// - /// The chain to append to. - /// Item 7. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T7 item7 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size; - var newSize = originalSize + item7Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - // Append the last structure - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - } - - /// - /// Creates a new with 9 items, by appending to - /// the end of this chain. - /// - /// Item 8. - /// Type of Item 8 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T8 item8 = default) - where T8 : struct, IExtendsChain - { - return new ManagedChain(this, item8); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item7Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef((Chain*) _item7Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item8Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef((Chain*) _item8Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 9 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - } - - /// - /// Creates a new with 9 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 9"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 9"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 9"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 9"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 9"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 9"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T7 item7 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 9"); - else - { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item7 = Unsafe.AsRef(currentPtr); - } - - var item7Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T8 item8 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 9"); - else - { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item8 = Unsafe.AsRef(currentPtr); - } - - var item8Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - } - - /// - /// Creates a new with 9 items. - /// - /// The chain to append to. - /// Item 8. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T8 item8 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size; - var newSize = originalSize + item8Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - // Append the last structure - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - } - - /// - /// Creates a new with 10 items, by appending to - /// the end of this chain. - /// - /// Item 9. - /// Type of Item 9 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T9 item9 = default) - where T9 : struct, IExtendsChain - { - return new ManagedChain(this, item9); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -/// Type of Item 9. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item7Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef((Chain*) _item7Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item8Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef((Chain*) _item8Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item9Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; - - /// - /// Gets or sets item #9 in the chain. - /// - public T9 Item9 - { - get => Unsafe.AsRef((Chain*) _item9Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 10 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, - T9 item9 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - } - - /// - /// Creates a new with 10 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 10"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 10"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 10"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 10"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 10"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 10"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T7 item7 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 10"); - else - { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item7 = Unsafe.AsRef(currentPtr); - } - - var item7Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T8 item8 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 10"); - else - { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item8 = Unsafe.AsRef(currentPtr); - } - - var item8Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T9 item9 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 10"); - else - { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item9 = Unsafe.AsRef(currentPtr); - } - - var item9Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - } - - /// - /// Creates a new with 10 items. - /// - /// The chain to append to. - /// Item 9. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T9 item9 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + - item7Size + item8Size; - var newSize = originalSize + item9Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - // Append the last structure - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - } - - /// - /// Creates a new with 11 items, by appending to - /// the end of this chain. - /// - /// Item 10. - /// Type of Item 10 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T10 item10 = default) - where T10 : struct, IExtendsChain - { - return new ManagedChain(this, item10); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -/// Type of Item 9. -/// Type of Item 10. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item7Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef((Chain*) _item7Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item8Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef((Chain*) _item8Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item9Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; - - /// - /// Gets or sets item #9 in the chain. - /// - public T9 Item9 - { - get => Unsafe.AsRef((Chain*) _item9Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item10Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; - - /// - /// Gets or sets item #10 in the chain. - /// - public T10 Item10 - { - get => Unsafe.AsRef((Chain*) _item10Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 11 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, - T9 item9 = default, T10 item10 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - } - - /// - /// Creates a new with 11 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 11"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 11"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 11"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 11"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 11"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 11"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T7 item7 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 11"); - else - { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item7 = Unsafe.AsRef(currentPtr); - } - - var item7Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T8 item8 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 11"); - else - { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item8 = Unsafe.AsRef(currentPtr); - } - - var item8Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T9 item9 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 11"); - else - { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item9 = Unsafe.AsRef(currentPtr); - } - - var item9Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T10 item10 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 11"); - else - { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item10 = Unsafe.AsRef(currentPtr); - } - - var item10Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - } - - /// - /// Creates a new with 11 items. - /// - /// The chain to append to. - /// Item 10. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T10 item10 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + - item7Size + item8Size + item9Size; - var newSize = originalSize + item10Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - // Append the last structure - item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - } - - /// - /// Creates a new with 12 items, by appending to - /// the end of this chain. - /// - /// Item 11. - /// Type of Item 11 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T11 item11 = default) - where T11 : struct, IExtendsChain - { - return new ManagedChain(this, item11); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -/// Type of Item 9. -/// Type of Item 10. -/// Type of Item 11. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item7Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef((Chain*) _item7Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item8Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef((Chain*) _item8Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item9Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; - - /// - /// Gets or sets item #9 in the chain. - /// - public T9 Item9 - { - get => Unsafe.AsRef((Chain*) _item9Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item10Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; - - /// - /// Gets or sets item #10 in the chain. - /// - public T10 Item10 - { - get => Unsafe.AsRef((Chain*) _item10Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item11Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; - - /// - /// Gets or sets item #11 in the chain. - /// - public T11 Item11 - { - get => Unsafe.AsRef((Chain*) _item11Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 12 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, - T9 item9 = default, T10 item10 = default, T11 item11 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - } - - /// - /// Creates a new with 12 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 12"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 12"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 12"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 12"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 12"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 12"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T7 item7 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 12"); - else - { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item7 = Unsafe.AsRef(currentPtr); - } - - var item7Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T8 item8 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 12"); - else - { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item8 = Unsafe.AsRef(currentPtr); - } - - var item8Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T9 item9 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 12"); - else - { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item9 = Unsafe.AsRef(currentPtr); - } - - var item9Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T10 item10 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 12"); - else - { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item10 = Unsafe.AsRef(currentPtr); - } - - var item10Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T11 item11 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 12"); - else - { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item11 = Unsafe.AsRef(currentPtr); - } - - var item11Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - } - - /// - /// Creates a new with 12 items. - /// - /// The chain to append to. - /// Item 11. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T11 item11 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + - item7Size + item8Size + item9Size + item10Size; - var newSize = originalSize + item11Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - // Append the last structure - item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - } - - /// - /// Creates a new with 13 items, by appending to - /// the end of this chain. - /// - /// Item 12. - /// Type of Item 12 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T12 item12 = default) - where T12 : struct, IExtendsChain - { - return new ManagedChain(this, item12); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -/// Type of Item 9. -/// Type of Item 10. -/// Type of Item 11. -/// Type of Item 12. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item7Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef((Chain*) _item7Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item8Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef((Chain*) _item8Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item9Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; - - /// - /// Gets or sets item #9 in the chain. - /// - public T9 Item9 - { - get => Unsafe.AsRef((Chain*) _item9Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item10Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; - - /// - /// Gets or sets item #10 in the chain. - /// - public T10 Item10 - { - get => Unsafe.AsRef((Chain*) _item10Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item11Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; - - /// - /// Gets or sets item #11 in the chain. - /// - public T11 Item11 - { - get => Unsafe.AsRef((Chain*) _item11Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item12Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item12Ptr => (Chain*) _item12Ptr; - - /// - /// Gets or sets item #12 in the chain. - /// - public T12 Item12 - { - get => Unsafe.AsRef((Chain*) _item12Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item12Ptr)->PNext; - Marshal.StructureToPtr(value, _item12Ptr, true); - ((Chain*) _item12Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 13 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, - T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + - item12Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - } - - /// - /// Creates a new with 13 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 13"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 13"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 13"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 13"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 13"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 13"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T7 item7 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 13"); - else - { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item7 = Unsafe.AsRef(currentPtr); - } - - var item7Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T8 item8 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 13"); - else - { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item8 = Unsafe.AsRef(currentPtr); - } - - var item8Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T9 item9 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 13"); - else - { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item9 = Unsafe.AsRef(currentPtr); - } - - var item9Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T10 item10 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 13"); - else - { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item10 = Unsafe.AsRef(currentPtr); - } - - var item10Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T11 item11 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 13"); - else - { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item11 = Unsafe.AsRef(currentPtr); - } - - var item11Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T12 item12 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 13"); - else - { - expectedStructureType = item12.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 13; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item12 = Unsafe.AsRef(currentPtr); - } - - var item12Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + - item12Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - } - - /// - /// Creates a new with 13 items. - /// - /// The chain to append to. - /// Item 12. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, - T12 item12 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + - item7Size + item8Size + item9Size + item10Size + item11Size; - var newSize = originalSize + item12Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - // Append the last structure - item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - } - - /// - /// Creates a new with 14 items, by appending to - /// the end of this chain. - /// - /// Item 13. - /// Type of Item 13 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append( - T13 item13 = default) - where T13 : struct, IExtendsChain - { - return new ManagedChain(this, item13); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); - var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item12Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -/// Type of Item 9. -/// Type of Item 10. -/// Type of Item 11. -/// Type of Item 12. -/// Type of Item 13. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item7Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef((Chain*) _item7Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item8Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef((Chain*) _item8Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item9Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; - - /// - /// Gets or sets item #9 in the chain. - /// - public T9 Item9 - { - get => Unsafe.AsRef((Chain*) _item9Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item10Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; - - /// - /// Gets or sets item #10 in the chain. - /// - public T10 Item10 - { - get => Unsafe.AsRef((Chain*) _item10Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item11Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; - - /// - /// Gets or sets item #11 in the chain. - /// - public T11 Item11 - { - get => Unsafe.AsRef((Chain*) _item11Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item12Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item12Ptr => (Chain*) _item12Ptr; - - /// - /// Gets or sets item #12 in the chain. - /// - public T12 Item12 - { - get => Unsafe.AsRef((Chain*) _item12Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item12Ptr)->PNext; - Marshal.StructureToPtr(value, _item12Ptr, true); - ((Chain*) _item12Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item13Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item13Ptr => (Chain*) _item13Ptr; - - /// - /// Gets or sets item #13 in the chain. - /// - public T13 Item13 - { - get => Unsafe.AsRef((Chain*) _item13Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item13Ptr)->PNext; - Marshal.StructureToPtr(value, _item13Ptr, true); - ((Chain*) _item13Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 14 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, - T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + - item12Size + item13Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - item13.StructureType(); - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - } - - /// - /// Creates a new with 14 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 14"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 14"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 14"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 14"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 14"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 14"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T7 item7 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 14"); - else - { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item7 = Unsafe.AsRef(currentPtr); - } - - var item7Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T8 item8 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 14"); - else - { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item8 = Unsafe.AsRef(currentPtr); - } - - var item8Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T9 item9 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 14"); - else - { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item9 = Unsafe.AsRef(currentPtr); - } - - var item9Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T10 item10 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 14"); - else - { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item10 = Unsafe.AsRef(currentPtr); - } - - var item10Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T11 item11 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 14"); - else - { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item11 = Unsafe.AsRef(currentPtr); - } - - var item11Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T12 item12 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 14"); - else - { - expectedStructureType = item12.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 13; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item12 = Unsafe.AsRef(currentPtr); - } - - var item12Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T13 item13 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 14"); - else - { - expectedStructureType = item13.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 14; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item13 = Unsafe.AsRef(currentPtr); - } - - var item13Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + - item12Size + item13Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - } - - /// - /// Creates a new with 14 items. - /// - /// The chain to append to. - /// Item 13. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, - T13 item13 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + - item7Size + item8Size + item9Size + item10Size + item11Size + item12Size; - var newSize = originalSize + item13Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - // Append the last structure - item13.StructureType(); - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - } - - /// - /// Creates a new with 15 items, by appending to - /// the end of this chain. - /// - /// Item 14. - /// Type of Item 14 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append( - T14 item14 = default) - where T14 : struct, IExtendsChain - { - return new ManagedChain(this, item14); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); - var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item12Ptr); - var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item13Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -/// Type of Item 9. -/// Type of Item 10. -/// Type of Item 11. -/// Type of Item 12. -/// Type of Item 13. -/// Type of Item 14. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item7Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef((Chain*) _item7Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item8Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef((Chain*) _item8Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item9Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; - - /// - /// Gets or sets item #9 in the chain. - /// - public T9 Item9 - { - get => Unsafe.AsRef((Chain*) _item9Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item10Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; - - /// - /// Gets or sets item #10 in the chain. - /// - public T10 Item10 - { - get => Unsafe.AsRef((Chain*) _item10Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item11Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; - - /// - /// Gets or sets item #11 in the chain. - /// - public T11 Item11 - { - get => Unsafe.AsRef((Chain*) _item11Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item12Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item12Ptr => (Chain*) _item12Ptr; - - /// - /// Gets or sets item #12 in the chain. - /// - public T12 Item12 - { - get => Unsafe.AsRef((Chain*) _item12Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item12Ptr)->PNext; - Marshal.StructureToPtr(value, _item12Ptr, true); - ((Chain*) _item12Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item13Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item13Ptr => (Chain*) _item13Ptr; - - /// - /// Gets or sets item #13 in the chain. - /// - public T13 Item13 - { - get => Unsafe.AsRef((Chain*) _item13Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item13Ptr)->PNext; - Marshal.StructureToPtr(value, _item13Ptr, true); - ((Chain*) _item13Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item14Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item14Ptr => (Chain*) _item14Ptr; - - /// - /// Gets or sets item #14 in the chain. - /// - public T14 Item14 - { - get => Unsafe.AsRef((Chain*) _item14Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item14Ptr)->PNext; - Marshal.StructureToPtr(value, _item14Ptr, true); - ((Chain*) _item14Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 15 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - /// Item 14. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, - T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, - T14 item14 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - var item14Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + - item12Size + item13Size + item14Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - item13.StructureType(); - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; - item14.StructureType(); - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; - } - - /// - /// Creates a new with 15 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 15"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 15"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 15"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 15"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 15"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 15"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T7 item7 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 15"); - else - { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item7 = Unsafe.AsRef(currentPtr); - } - - var item7Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T8 item8 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 15"); - else - { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item8 = Unsafe.AsRef(currentPtr); - } - - var item8Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T9 item9 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 15"); - else - { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item9 = Unsafe.AsRef(currentPtr); - } - - var item9Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T10 item10 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 15"); - else - { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item10 = Unsafe.AsRef(currentPtr); - } - - var item10Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T11 item11 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 15"); - else - { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item11 = Unsafe.AsRef(currentPtr); - } - - var item11Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T12 item12 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 15"); - else - { - expectedStructureType = item12.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 13; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item12 = Unsafe.AsRef(currentPtr); - } - - var item12Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T13 item13 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 15"); - else - { - expectedStructureType = item13.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 14; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item13 = Unsafe.AsRef(currentPtr); - } - - var item13Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T14 item14 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 15"); - else - { - expectedStructureType = item14.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 15; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item14 = Unsafe.AsRef(currentPtr); - } - - var item14Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + - item12Size + item13Size + item14Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; - } - - /// - /// Creates a new with 15 items. - /// - /// The chain to append to. - /// Item 14. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, - T14 item14 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - var item14Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + - item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size; - var newSize = originalSize + item14Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; - // Append the last structure - item14.StructureType(); - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; - } - - /// - /// Creates a new with 16 items, by appending to - /// the end of this chain. - /// - /// Item 15. - /// Type of Item 15 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append( - T15 item15 = default) - where T15 : struct, IExtendsChain - { - return new ManagedChain(this, item15); - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); - var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item12Ptr); - var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item13Ptr); - var item14Ptr = Interlocked.Exchange(ref _item14Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item14Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -/// Type of Item 9. -/// Type of Item 10. -/// Type of Item 11. -/// Type of Item 12. -/// Type of Item 13. -/// Type of Item 14. -/// Type of Item 15. -public unsafe class ManagedChain : IDisposable - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain - where T15 : struct, IExtendsChain -{ - private IntPtr _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item2Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item3Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef((Chain*) _item3Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item4Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef((Chain*) _item4Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item5Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef((Chain*) _item5Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item6Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef((Chain*) _item6Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item7Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef((Chain*) _item7Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item8Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef((Chain*) _item8Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item9Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; - - /// - /// Gets or sets item #9 in the chain. - /// - public T9 Item9 - { - get => Unsafe.AsRef((Chain*) _item9Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item10Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; - - /// - /// Gets or sets item #10 in the chain. - /// - public T10 Item10 - { - get => Unsafe.AsRef((Chain*) _item10Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item11Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; - - /// - /// Gets or sets item #11 in the chain. - /// - public T11 Item11 - { - get => Unsafe.AsRef((Chain*) _item11Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item12Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item12Ptr => (Chain*) _item12Ptr; - - /// - /// Gets or sets item #12 in the chain. - /// - public T12 Item12 - { - get => Unsafe.AsRef((Chain*) _item12Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item12Ptr)->PNext; - Marshal.StructureToPtr(value, _item12Ptr, true); - ((Chain*) _item12Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item13Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item13Ptr => (Chain*) _item13Ptr; - - /// - /// Gets or sets item #13 in the chain. - /// - public T13 Item13 - { - get => Unsafe.AsRef((Chain*) _item13Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item13Ptr)->PNext; - Marshal.StructureToPtr(value, _item13Ptr, true); - ((Chain*) _item13Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item14Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item14Ptr => (Chain*) _item14Ptr; - - /// - /// Gets or sets item #14 in the chain. - /// - public T14 Item14 - { - get => Unsafe.AsRef((Chain*) _item14Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item14Ptr)->PNext; - Marshal.StructureToPtr(value, _item14Ptr, true); - ((Chain*) _item14Ptr)->PNext = nextPtr; - } - } - - private IntPtr _item15Ptr; - - /// - /// Gets a pointer to the second item in the chain. - /// - public Chain* Item15Ptr => (Chain*) _item15Ptr; - - /// - /// Gets or sets item #15 in the chain. - /// - public T15 Item15 - { - get => Unsafe.AsRef((Chain*) _item15Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item15Ptr)->PNext; - Marshal.StructureToPtr(value, _item15Ptr, true); - ((Chain*) _item15Ptr)->PNext = nextPtr; - } - } - - /// - /// Creates a new with 16 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - /// Item 14. - /// Item 15. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, - T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, - T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, - T14 item14 = default, T15 item15 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - var item14Size = Marshal.SizeOf(); - var item15Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + - item12Size + item13Size + item14Size + item15Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - item13.StructureType(); - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; - item14.StructureType(); - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; - - _item15Ptr = _item14Ptr + item14Size; - item15.StructureType(); - Marshal.StructureToPtr(item15, _item15Ptr, false); - ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; - } - - /// - /// Creates a new with 16 items from an existing unmanaged chain. - /// - /// The unmanaged chain to use as the basis of this chain. - /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) - { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - var errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 16"); - else - { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item1 = Unsafe.AsRef(currentPtr); - } - - var item1Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 16"); - else - { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item2 = Unsafe.AsRef(currentPtr); - } - - var item2Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 16"); - else - { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item3 = Unsafe.AsRef(currentPtr); - } - - var item3Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T4 item4 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 16"); - else - { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item4 = Unsafe.AsRef(currentPtr); - } - - var item4Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T5 item5 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 16"); - else - { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item5 = Unsafe.AsRef(currentPtr); - } - - var item5Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T6 item6 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 16"); - else - { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item6 = Unsafe.AsRef(currentPtr); - } - - var item6Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T7 item7 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 16"); - else - { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item7 = Unsafe.AsRef(currentPtr); - } - - var item7Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T8 item8 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 16"); - else - { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item8 = Unsafe.AsRef(currentPtr); - } - - var item8Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T9 item9 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 16"); - else - { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item9 = Unsafe.AsRef(currentPtr); - } - - var item9Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T10 item10 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 16"); - else - { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item10 = Unsafe.AsRef(currentPtr); - } - - var item10Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T11 item11 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 16"); - else - { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item11 = Unsafe.AsRef(currentPtr); - } - - var item11Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T12 item12 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 16"); - else - { - expectedStructureType = item12.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 13; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item12 = Unsafe.AsRef(currentPtr); - } - - var item12Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T13 item13 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 16"); - else - { - expectedStructureType = item13.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 14; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item13 = Unsafe.AsRef(currentPtr); - } - - var item13Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T14 item14 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 16"); - else - { - expectedStructureType = item14.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 15; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item14 = Unsafe.AsRef(currentPtr); - } - - var item14Size = Marshal.SizeOf(); - - currentPtr = currentPtr->PNext; - T15 item15 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 15, expected length 16"); - else - { - expectedStructureType = item15.StructureType(); - if (currentPtr->SType != expectedStructureType) - { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 16; expected ") - .Append(expectedStructureType) - .AppendLine(); - } - else - item15 = Unsafe.AsRef(currentPtr); - } - - var item15Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + - item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + - item12Size + item13Size + item14Size + item15Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; - - _item15Ptr = _item14Ptr + item14Size; - Marshal.StructureToPtr(item15, _item15Ptr, false); - ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; - } - - /// - /// Creates a new with 16 items. - /// - /// The chain to append to. - /// Item 15. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, - T15 item15 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - var item14Size = Marshal.SizeOf(); - var item15Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + - item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + - item14Size; - var newSize = originalSize + item15Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*) _headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; - - _item15Ptr = _item14Ptr + item14Size; - // Append the last structure - item15.StructureType(); - Marshal.StructureToPtr(item15, _item15Ptr, false); - ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; - } - - /// - public void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); - var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item12Ptr); - var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item13Ptr); - var item14Ptr = Interlocked.Exchange(ref _item14Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item14Ptr); - var item15Ptr = Interlocked.Exchange(ref _item15Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item15Ptr); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} \ No newline at end of file diff --git a/PrototypeStructChaining/ManagedChain.gen.tt b/PrototypeStructChaining/ManagedChain.gen.tt index cb91403f6c..997583ede4 100644 --- a/PrototypeStructChaining/ManagedChain.gen.tt +++ b/PrototypeStructChaining/ManagedChain.gen.tt @@ -2,7 +2,7 @@ <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <# - var maximumItems = 16; + var maximumItems = 5; string parameterDocs(int index, string prefix) { @@ -95,6 +95,7 @@ return builder.ToString(); } #> +using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -104,8 +105,24 @@ namespace Silk.Net.Vulkan; /// /// Static class for creating Managed Chains. /// -public static class ManagedChain +public abstract class ManagedChain : IReadOnlyList, IDisposable { + /// + public abstract IEnumerator GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + public abstract int Count { get; } + + /// + public abstract IChainable this[int index] { get; } + + /// + public abstract void Dispose(); + <# for (var i = 2; i <= maximumItems; i++) { @@ -137,7 +154,7 @@ public static class ManagedChain /// A safely manages the pointers of a managed structure chain. /// <#= parameterTypeDocs(i, "/// ") #> -public unsafe class ManagedChain<<#= tList #>> : IDisposable +public unsafe class ManagedChain<<#= tList #>> : ManagedChain <#= constraintList(i, " ") #> { private IntPtr _headPtr; @@ -257,13 +274,13 @@ public unsafe class ManagedChain<<#= tList #>> : IDisposable errorBuilder.AppendLine("The unmanaged chain was length <#= j #>, expected length <#= i #>"); else { expectedStructureType = item<#= j #>.StructureType(); - if (currentPtr->SType != expectedStructureType) + if (currentPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(currentPtr->SType) .Append(" at position <#= j + 1 #>; expected ") .Append(expectedStructureType) .AppendLine(); - else + } else item<#= j #> = Unsafe.AsRef>(currentPtr); } var item<#= j #>Size = Marshal.SizeOf>(); @@ -384,7 +401,39 @@ public unsafe class ManagedChain<<#= tList #>> : IDisposable #> /// - public void Dispose() + public override IEnumerator GetEnumerator() + { + yield return Head; +<# + for (var j = 1; j < i; j++) + { +#> + yield return Item<#= j #>; +<# + } // for (int j = 1; j < i; j++) { +#> + } + + /// + public override int Count => <#= i #>; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head,<# + for (var j = 1; j < i; j++) + { +#> + <#= j #> => Item<#= j #>, +<# + } // for (int j = 1; j < i; j++) { +#> + _ => throw new IndexOutOfRangeException() + }; + + /// + public override void Dispose() { var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); if (headPtr == IntPtr.Zero) return; diff --git a/PrototypeStructChaining/PrototypeStructChaining.csproj b/PrototypeStructChaining/PrototypeStructChaining.csproj index 7feb76b14e..5a7f851a90 100644 --- a/PrototypeStructChaining/PrototypeStructChaining.csproj +++ b/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0 + netstandard2.0 10 enable enable @@ -10,13 +10,13 @@ - - - - - - - + + + + + + + @@ -28,14 +28,14 @@ - True - True - ManagedChain.gen.tt + True + True + ManagedChain.gen.tt - True - True - ManagedChain.gen.tt + True + True + ManagedChain.gen.tt diff --git a/Readme.md b/Readme.md index 4f51bfb5ad..03be89248f 100644 --- a/Readme.md +++ b/Readme.md @@ -335,4 +335,31 @@ The unmanaged chain was length 4, expected length 5", // Despite the errors indexing features was at the right location so was loaded Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); -``` \ No newline at end of file +``` + +### IReadOnlyList + +All the fully generic `ManageChain` types extend `ManagedChain` which implements `IDisposable` +and `IReadOnlyList`. The latter allowing for easy consumption of any `ManagedChain`, e.g.: + +```csharp +using var chain = new ManagedChain(); + +Assert.Equal(3, chain.Count); + +// Ensure all STypes set correctly using indexer +Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain[0].StructureType()); +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain[1].StructureType()); +Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain[2].StructureType()); + +Assert.Throws(() => chain[3]); + +// Get array using IEnumerable implementation +IChainable[] structures = chain.ToArray(); + +// Check concrete types +Assert.IsType(structures[0]); +Assert.IsType(structures[1]); +Assert.IsType(structures[2]); +``` From 5254b9d454c314edbd02f103176c95b336a80b6e Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sat, 6 Nov 2021 16:03:44 +0000 Subject: [PATCH 15/34] feat: Added deconstructor to `ManageChain<...>` --- .../TestManagedChains.cs | 14 +++++ PrototypeStructChaining/ManagedChain.gen.cs | 56 +++++++++++++++++++ PrototypeStructChaining/ManagedChain.gen.tt | 24 +++++++- Readme.md | 11 ++++ 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/PrototypeStructChaining.Test/TestManagedChains.cs b/PrototypeStructChaining.Test/TestManagedChains.cs index 6708f88bad..baa568926a 100644 --- a/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/PrototypeStructChaining.Test/TestManagedChains.cs @@ -233,4 +233,18 @@ public unsafe void TestReadOnlyList() Assert.IsType(structures[1]); Assert.IsType(structures[2]); } + + [Fact] + public unsafe void TestDeconstructor() + { + using var chain = new ManagedChain(); + + var (physicalDeviceFeatures2, indexingFeatures, accelerationStructureFeaturesKhr) = chain; + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, physicalDeviceFeatures2.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeaturesKhr.SType); + } } \ No newline at end of file diff --git a/PrototypeStructChaining/ManagedChain.gen.cs b/PrototypeStructChaining/ManagedChain.gen.cs index 6d3e16ebc9..b927d6bf7d 100644 --- a/PrototypeStructChaining/ManagedChain.gen.cs +++ b/PrototypeStructChaining/ManagedChain.gen.cs @@ -256,6 +256,17 @@ public override IChainable this[int index] _ => throw new IndexOutOfRangeException() }; + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + public void Deconstruct(out TChain head, out T1 item1) + { + head = Head; + item1 = Item1; + } + /// public override void Dispose() { @@ -507,6 +518,19 @@ public override IChainable this[int index] _ => throw new IndexOutOfRangeException() }; + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2) + { + head = Head; + item1 = Item1; + item2 = Item2; + } + /// public override void Dispose() { @@ -817,6 +841,21 @@ public override IChainable this[int index] _ => throw new IndexOutOfRangeException() }; + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + } + /// public override void Dispose() { @@ -1171,6 +1210,23 @@ public override IChainable this[int index] _ => throw new IndexOutOfRangeException() }; + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + } + /// public override void Dispose() { diff --git a/PrototypeStructChaining/ManagedChain.gen.tt b/PrototypeStructChaining/ManagedChain.gen.tt index 997583ede4..7c1b6c98ac 100644 --- a/PrototypeStructChaining/ManagedChain.gen.tt +++ b/PrototypeStructChaining/ManagedChain.gen.tt @@ -2,7 +2,7 @@ <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <# - var maximumItems = 5; + var maximumItems = 5; // TODO use 16/32 in production string parameterDocs(int index, string prefix) { @@ -432,6 +432,28 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain _ => throw new IndexOutOfRangeException() }; + /// + /// Deconstructs this chain. + /// +<#= parameterDocs(i, " /// ") #> + public void Deconstruct(out TChain head<# + for (var j = 1; j < i; j++) + { +#>, out T<#= j #> item<#= j #><# + } // for (int j = 1; j < i; j++) { +#>) + { + head = Head; +<# + for (var j = 1; j < i; j++) + { +#> + item<#= j #> = Item<#= j #>; +<# + } // for (int j = 1; j < i; j++) { +#> + } + /// public override void Dispose() { diff --git a/Readme.md b/Readme.md index 03be89248f..dd3131311d 100644 --- a/Readme.md +++ b/Readme.md @@ -363,3 +363,14 @@ Assert.IsType(structures[0]); Assert.IsType(structures[1]); Assert.IsType(structures[2]); ``` + +### Deconstructor + +Each `ManageChain` has a corresponding deconstructor for convenience, e.g.: + +```csharp +``` + +# TODOS + +- Add `Load` static methods to `ManagedChain` to call the `ManagedChain(TChain chain, out string errors)` constructors. \ No newline at end of file From 8d3f124255fcb6bde7f6ed68d00971a3c4446e59 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sat, 6 Nov 2021 16:28:50 +0000 Subject: [PATCH 16/34] feat: Added static `ManagedChain.Load` Also improved loading to detect when the unmanaged chain is too long. --- .../TestManagedChains.cs | 34 ++++- PrototypeStructChaining/ManagedChain.gen.cs | 140 +++++++++++++++++- PrototypeStructChaining/ManagedChain.gen.tt | 37 ++++- Readme.md | 35 +++-- 4 files changed, 223 insertions(+), 23 deletions(-) diff --git a/PrototypeStructChaining.Test/TestManagedChains.cs b/PrototypeStructChaining.Test/TestManagedChains.cs index baa568926a..9e36831cbd 100644 --- a/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/PrototypeStructChaining.Test/TestManagedChains.cs @@ -157,7 +157,7 @@ public unsafe void TestManagedChainLoad() // Loads a new managed chain from an unmanaged chain using var managedChain = new ManagedChain(unmanagedChain, out var errors); + PhysicalDeviceAccelerationStructureFeaturesKHR>(out var errors, unmanagedChain); // Check we had no loading errors Assert.Equal("", errors); @@ -192,14 +192,14 @@ public unsafe void TestManagedChainLoadWithError() // Loads a new managed chain from an unmanaged chain using var managedChain = - new ManagedChain< + ManagedChain.Load< DeviceCreateInfo, // Note we are supplied a PhysicalDeviceFeatures2 here from the unmanaged chain PhysicalDeviceAccelerationStructureFeaturesKHR, PhysicalDeviceDescriptorIndexingFeatures, PhysicalDeviceAccelerationStructureFeaturesKHR, // Note that the unmanaged chain did not supply a 5th entry - PhysicalDeviceFeatures2>(unmanagedChain, out var errors); + PhysicalDeviceFeatures2>(out var errors, unmanagedChain); // Check for errors Assert.Equal( @@ -210,6 +210,34 @@ public unsafe void TestManagedChainLoadWithError() Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); } + [Fact] + public unsafe void TestManagedChainLoadWithErrorTooLong() + { + var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + { + ShaderInputAttachmentArrayDynamicIndexing = true + }; + // Load an unmanaged chain + DeviceCreateInfo + .Chain(out var unmanagedChain) + .AddNext(out PhysicalDeviceFeatures2 features2) + .SetNext(ref indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + + // Try loading a shorter managed chain + using var managedChain = + ManagedChain.Load< + DeviceCreateInfo, + PhysicalDeviceFeatures2, + PhysicalDeviceDescriptorIndexingFeatures>(out var errors, unmanagedChain); + + // Check for errors + Assert.Equal(@"The unmanaged chain was longer than the expected length 3", errors); + + // Despite the errors indexing features was at the right location so was loaded + Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); + } + [Fact] public unsafe void TestReadOnlyList() { diff --git a/PrototypeStructChaining/ManagedChain.gen.cs b/PrototypeStructChaining/ManagedChain.gen.cs index b927d6bf7d..6e41217355 100644 --- a/PrototypeStructChaining/ManagedChain.gen.cs +++ b/PrototypeStructChaining/ManagedChain.gen.cs @@ -41,6 +41,32 @@ public static ManagedChain Create(TChain head = default, return new(head, item1); } + /// + /// Loads a new with 2 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 2 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 2 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 2 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + { + return new(out var _, chain); + } + /// /// Creates a new with 3 items. /// @@ -59,6 +85,34 @@ public static ManagedChain Create(TChain head = return new(head, item1, item2); } + /// + /// Loads a new with 3 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 3 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 3 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 3 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + { + return new(out var _, chain); + } + /// /// Creates a new with 4 items. /// @@ -80,6 +134,36 @@ public static ManagedChain Create(TChain return new(head, item1, item2, item3); } + /// + /// Loads a new with 4 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 4 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 4 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 4 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + { + return new(out var _, chain); + } + /// /// Creates a new with 5 items. /// @@ -104,6 +188,38 @@ public static ManagedChain Create + /// Loads a new with 5 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 5 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 5 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 5 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + { + return new(out var _, chain); + } + } /// @@ -183,9 +299,9 @@ public ManagedChain(TChain head = default, T1 item1 = default) /// /// Creates a new with 2 items from an existing unmanaged chain. /// - /// The unmanaged chain to use as the basis of this chain. /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) { // Load existing chain first, so any errors occur before we allocate memory var head = chain; @@ -208,6 +324,8 @@ public ManagedChain(TChain chain, out string errors) .AppendLine(); } else item1 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); } var item1Size = Marshal.SizeOf(); @@ -390,9 +508,9 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// /// Creates a new with 3 items from an existing unmanaged chain. /// - /// The unmanaged chain to use as the basis of this chain. /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) { // Load existing chain first, so any errors occur before we allocate memory var head = chain; @@ -432,6 +550,8 @@ public ManagedChain(TChain chain, out string errors) .AppendLine(); } else item2 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 3"); } var item2Size = Marshal.SizeOf(); @@ -686,9 +806,9 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// /// Creates a new with 4 items from an existing unmanaged chain. /// - /// The unmanaged chain to use as the basis of this chain. /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) { // Load existing chain first, so any errors occur before we allocate memory var head = chain; @@ -745,6 +865,8 @@ public ManagedChain(TChain chain, out string errors) .AppendLine(); } else item3 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 4"); } var item3Size = Marshal.SizeOf(); @@ -1043,9 +1165,9 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// /// Creates a new with 5 items from an existing unmanaged chain. /// - /// The unmanaged chain to use as the basis of this chain. /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) { // Load existing chain first, so any errors occur before we allocate memory var head = chain; @@ -1119,6 +1241,8 @@ public ManagedChain(TChain chain, out string errors) .AppendLine(); } else item4 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 5"); } var item4Size = Marshal.SizeOf(); diff --git a/PrototypeStructChaining/ManagedChain.gen.tt b/PrototypeStructChaining/ManagedChain.gen.tt index 7c1b6c98ac..3747a699c9 100644 --- a/PrototypeStructChaining/ManagedChain.gen.tt +++ b/PrototypeStructChaining/ManagedChain.gen.tt @@ -140,6 +140,30 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable return new(<#= argList(i) #>); } + /// + /// Loads a new with <#= i #> items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with <#= i #> items. + public static ManagedChain<<#= tList #>> Load<<#= tList #>>(out string errors, TChain chain) +<#= constraintList(i, " ") #> + { + return new(out errors, chain); + } + + /// + /// Loads a new with <#= i #> items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with <#= i #> items. + public static ManagedChain<<#= tList #>> Load<<#= tList #>>(TChain chain) +<#= constraintList(i, " ") #> + { + return new(out var _, chain); + } + <# } // for (var 2 = 1; i <= maximumItems; i++) { #> @@ -253,9 +277,9 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain /// /// Creates a new with <#= i #> items from an existing unmanaged chain. /// - /// The unmanaged chain to use as the basis of this chain. /// Any errors loading the chain. - public ManagedChain(TChain chain, out string errors) + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) { // Load existing chain first, so any errors occur before we allocate memory var head = chain; @@ -282,6 +306,15 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain .AppendLine(); } else item<#= j #> = Unsafe.AsRef>(currentPtr); +<# + if (j == i -1) + { +#> + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length <#= i #>"); +<# + } // if (j == i -1) +#> } var item<#= j #>Size = Marshal.SizeOf>(); diff --git a/Readme.md b/Readme.md index dd3131311d..c366a8eaa3 100644 --- a/Readme.md +++ b/Readme.md @@ -273,8 +273,8 @@ Assert.True(newChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); ### Loading from an unmanaged chain -If you have created an unmanaged chain and would like to load that into a `ManagedChain` you can supply it to a -constructor: +If you have created an unmanaged chain and would like to load that into a `ManagedChain` you can use one of the +`ManagedChain.Load` methods: ```csharp // Load an unmanaged chain @@ -289,7 +289,7 @@ PhysicalDeviceFeatures2 // Loads a new managed chain from an unmanaged chain using var managedChain = - new ManagedChain(unmanagedChain, out var errors); // Check we had no loading errors @@ -299,10 +299,12 @@ Assert.Equal("", errors); Assert.True(managedChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); ``` -Notice that this special form of the constructor returns an output parameter `errors`. It does this to prevent any -possible confusion with the normal constructor which also can accept a single parameter of type `TChain` (which will -only load the head of the chain). Secondly, it also allows the constructor to indicate any failures that occurred whilst -loading from the unmanaged type, for example: +The full version of the `Load` method returns an output parameter `errors` as it's first parameter. The `errors` +parameter will be `string.Empty` if there are no errors, otherwise each line will contain a separate error for each +issue found during loading. There is also an overload that accepts a single argument `chain` for when you don't care if +there are any errors. Either method always succeeds, even if the unmanaged chain doesn't match exactly - for example it +is shorter or longer than the chain being loaded, or if the managed chain has different structure types in any of the +positions. Any structure type in the expected position will always be loaded into the new `ManagedChain`. ```csharp var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures @@ -337,6 +339,8 @@ The unmanaged chain was length 4, expected length 5", Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); ``` +Notice that the above form use the constructor as an alternative. + ### IReadOnlyList All the fully generic `ManageChain` types extend `ManagedChain` which implements `IDisposable` @@ -364,13 +368,24 @@ Assert.IsType(structures[1]); Assert.IsType(structures[2]); ``` -### Deconstructor +### Deconstruction Each `ManageChain` has a corresponding deconstructor for convenience, e.g.: ```csharp +using var chain = new ManagedChain(); + +var (physicalDeviceFeatures2, indexingFeatures, accelerationStructureFeaturesKhr) = chain; + +// Ensure all STypes set correctly +Assert.Equal(StructureType.PhysicalDeviceFeatures2, physicalDeviceFeatures2.SType); +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); +Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeaturesKhr.SType); ``` -# TODOS +### Disposal -- Add `Load` static methods to `ManagedChain` to call the `ManagedChain(TChain chain, out string errors)` constructors. \ No newline at end of file +As each `ManagedChain` holds the underlying structures in unmanaged memory (to prevent them being moved and their +pointers being invalidated), then it is critical you dispose them; either by calling `Dispose()` or by using a `using` +statement. \ No newline at end of file From 80dac45186cdd71c0c939290f1df3411239e350e Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sat, 6 Nov 2021 16:37:09 +0000 Subject: [PATCH 17/34] chore: Readme.md updated --- Readme.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index c366a8eaa3..2eb68080a7 100644 --- a/Readme.md +++ b/Readme.md @@ -178,8 +178,10 @@ As adding `IChainStart` requires relatively simple logic I believe it's worth in ## ManagedChain Sometimes it is desirable to keep the structures around on the heap. To facilitate that you can use -the `ManagedChain` -types. Like `Tuple` et al, these support up to chain size 16. They should be disposed when finished with. +the `ManagedChain` types. Like `Tuple` et al, these support up to chain size 16. They must be +disposed when finished with. Whenever a structure is loaded into the `ManagedChain` it's `SType` and `PNext` are +forced to be correct, preventing errors. Structures can be replaced at any time, and we be inserted efficiently +into the chain as an O(1) operation. ### Creation From e74c9772ce58a869f526dc9b71d4b1def3b4b8eb Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sat, 6 Nov 2021 17:31:42 +0000 Subject: [PATCH 18/34] chore: Added Lab projects to Solution Also added the new blank proposals. --- ...uct Chaining - #1 StructureType correction.md | 16 ++++++++++++++++ ...an Struct Chaining - #2 Unmanaged Chaining.md | 16 ++++++++++++++++ ...lkan Struct Chaining - #3 Managed Chaining.md | 0 ...Chaining - #4 Chaining Metadata extensions.md | 16 ++++++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md create mode 100644 documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md create mode 100644 documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md create mode 100644 documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md new file mode 100644 index 0000000000..ef4927b2fb --- /dev/null +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md @@ -0,0 +1,16 @@ +# Summary + +# Contributors +- [Craig Dean, DevDecoder](https://github.com/thargy) + +# Current Status +- [x] Proposed +- [ ] Discussed with API Review Board (ARB) +- [ ] Approved +- [ ] Implemented + +# Design Decisions +This proposal purposely excludes window views as described in the views proposal, as barely any of the concepts +are applicable to mobile/view-based windowing platforms. + +# Proposed API diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md new file mode 100644 index 0000000000..ef4927b2fb --- /dev/null +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md @@ -0,0 +1,16 @@ +# Summary + +# Contributors +- [Craig Dean, DevDecoder](https://github.com/thargy) + +# Current Status +- [x] Proposed +- [ ] Discussed with API Review Board (ARB) +- [ ] Approved +- [ ] Implemented + +# Design Decisions +This proposal purposely excludes window views as described in the views proposal, as barely any of the concepts +are applicable to mobile/view-based windowing platforms. + +# Proposed API diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md new file mode 100644 index 0000000000..ef4927b2fb --- /dev/null +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md @@ -0,0 +1,16 @@ +# Summary + +# Contributors +- [Craig Dean, DevDecoder](https://github.com/thargy) + +# Current Status +- [x] Proposed +- [ ] Discussed with API Review Board (ARB) +- [ ] Approved +- [ ] Implemented + +# Design Decisions +This proposal purposely excludes window views as described in the views proposal, as barely any of the concepts +are applicable to mobile/view-based windowing platforms. + +# Proposed API From 3cae5ccdb0dee2ef6b2113800fd04c3461c2b139 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sat, 6 Nov 2021 17:34:03 +0000 Subject: [PATCH 19/34] chore: Fixed issues with previous commit --- Silk.NET.sln | 39 +++++++++++++++++-- ... Chaining - #1 StructureType correction.md | 7 ++-- ...Struct Chaining - #2 Unmanaged Chaining.md | 7 ++-- ...n Struct Chaining - #3 Managed Chaining.md | 17 ++++++++ ...ining - #4 Chaining Metadata extensions.md | 7 ++-- 5 files changed, 65 insertions(+), 12 deletions(-) diff --git a/Silk.NET.sln b/Silk.NET.sln index a56b4d0837..89381e3214 100644 --- a/Silk.NET.sln +++ b/Silk.NET.sln @@ -270,9 +270,9 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Silk.NET.NUKE", "build\nuke\Silk.NET.NUKE.csproj", "{B9A8D738-FE7D-4860-A446-4A03E3DDEB74}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft", "Microsoft", "{F2CF5D32-4B41-425E-B229-8FFC48F88063}" -ProjectSection(SolutionItems) = preProject - src\Microsoft\dxva.h = src\Microsoft\dxva.h -EndProjectSection + ProjectSection(SolutionItems) = preProject + src\Microsoft\dxva.h = src\Microsoft\dxva.h + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Silk.NET.Direct3D11", "src\Microsoft\Silk.NET.Direct3D11\Silk.NET.Direct3D11.csproj", "{F3B7A9D6-5B15-45E8-925B-20B5BBD33428}" EndProject @@ -468,6 +468,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.OpenXR.Extensions. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.OpenXR.Extensions.HTCX", "src\OpenXR\Extensions\Silk.NET.OpenXR.Extensions.HTCX\Silk.NET.OpenXR.Extensions.HTCX.csproj", "{782B6A7E-9F04-429A-9DCD-D7273AA3882E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PrototypeStructChaining", "PrototypeStructChaining", "{B15922CB-815C-4038-B635-EE2D8A8F700B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrototypeStructChaining", "src\Lab\Experiments\PrototypeStructChaining\PrototypeStructChaining\PrototypeStructChaining.csproj", "{EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrototypeStructChaining.Test", "src\Lab\Experiments\PrototypeStructChaining\PrototypeStructChaining.Test\PrototypeStructChaining.Test.csproj", "{BD19250B-E143-4F4E-9E1D-18829CCB3642}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2793,6 +2799,30 @@ Global {782B6A7E-9F04-429A-9DCD-D7273AA3882E}.Release|x64.Build.0 = Release|Any CPU {782B6A7E-9F04-429A-9DCD-D7273AA3882E}.Release|x86.ActiveCfg = Release|Any CPU {782B6A7E-9F04-429A-9DCD-D7273AA3882E}.Release|x86.Build.0 = Release|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Debug|x64.ActiveCfg = Debug|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Debug|x64.Build.0 = Debug|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Debug|x86.ActiveCfg = Debug|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Debug|x86.Build.0 = Debug|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Release|Any CPU.Build.0 = Release|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Release|x64.ActiveCfg = Release|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Release|x64.Build.0 = Release|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Release|x86.ActiveCfg = Release|Any CPU + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C}.Release|x86.Build.0 = Release|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Debug|x64.ActiveCfg = Debug|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Debug|x64.Build.0 = Debug|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Debug|x86.ActiveCfg = Debug|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Debug|x86.Build.0 = Debug|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Release|Any CPU.Build.0 = Release|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Release|x64.ActiveCfg = Release|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Release|x64.Build.0 = Release|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Release|x86.ActiveCfg = Release|Any CPU + {BD19250B-E143-4F4E-9E1D-18829CCB3642}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -3019,6 +3049,9 @@ Global {3E30D674-9282-4297-AD1F-9B233A166308} = {0651C5EF-50AA-4598-8D9C-8F210ADD8490} {606214B8-07FC-436F-9523-02AF32E1AB1E} = {90471225-AC23-424E-B62E-F6EC4C6ECAC0} {782B6A7E-9F04-429A-9DCD-D7273AA3882E} = {90471225-AC23-424E-B62E-F6EC4C6ECAC0} + {B15922CB-815C-4038-B635-EE2D8A8F700B} = {39B598E9-44BA-4A61-A1BB-7C543734DBA6} + {EEFF37DA-E4F2-406E-AF97-8615BB7BC34C} = {B15922CB-815C-4038-B635-EE2D8A8F700B} + {BD19250B-E143-4F4E-9E1D-18829CCB3642} = {B15922CB-815C-4038-B635-EE2D8A8F700B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F5273D7F-3334-48DF-94E3-41AE6816CD4D} diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md index ef4927b2fb..6039b01fcd 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md @@ -1,7 +1,8 @@ # Summary +TODO # Contributors -- [Craig Dean, DevDecoder](https://github.com/thargy) +- [Craig Dean, DevDecoder](https://github.com/thargy) # Current Status - [x] Proposed @@ -10,7 +11,7 @@ - [ ] Implemented # Design Decisions -This proposal purposely excludes window views as described in the views proposal, as barely any of the concepts -are applicable to mobile/view-based windowing platforms. +TODO # Proposed API +TODO \ No newline at end of file diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md index ef4927b2fb..6039b01fcd 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md @@ -1,7 +1,8 @@ # Summary +TODO # Contributors -- [Craig Dean, DevDecoder](https://github.com/thargy) +- [Craig Dean, DevDecoder](https://github.com/thargy) # Current Status - [x] Proposed @@ -10,7 +11,7 @@ - [ ] Implemented # Design Decisions -This proposal purposely excludes window views as described in the views proposal, as barely any of the concepts -are applicable to mobile/view-based windowing platforms. +TODO # Proposed API +TODO \ No newline at end of file diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md index e69de29bb2..6039b01fcd 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md @@ -0,0 +1,17 @@ +# Summary +TODO + +# Contributors +- [Craig Dean, DevDecoder](https://github.com/thargy) + +# Current Status +- [x] Proposed +- [ ] Discussed with API Review Board (ARB) +- [ ] Approved +- [ ] Implemented + +# Design Decisions +TODO + +# Proposed API +TODO \ No newline at end of file diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md index ef4927b2fb..6039b01fcd 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md @@ -1,7 +1,8 @@ # Summary +TODO # Contributors -- [Craig Dean, DevDecoder](https://github.com/thargy) +- [Craig Dean, DevDecoder](https://github.com/thargy) # Current Status - [x] Proposed @@ -10,7 +11,7 @@ - [ ] Implemented # Design Decisions -This proposal purposely excludes window views as described in the views proposal, as barely any of the concepts -are applicable to mobile/view-based windowing platforms. +TODO # Proposed API +TODO \ No newline at end of file From ef57171b7dac595182661e35f4ec4f8254933ae9 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sat, 6 Nov 2021 18:05:13 +0000 Subject: [PATCH 20/34] docs: Finished initial draft #1 Proposal - Vulkan Struct Chaining - #1 StructureType correction.md --- ... Chaining - #1 StructureType correction.md | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md index 6039b01fcd..d114a75fe2 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md @@ -1,17 +1,66 @@ # Summary -TODO + +This proposal is a minimal enhancement to [`Silk.Net.Vulkan`](../../src/Vulkan/Silk.NET.Vulkan) to mark all structures +that contain a `StructureType SType` field (in the first position) as implementing the interface `IStructuredType`. + +This is a tiny pre-requisite for +[Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) +and is of limited value otherwise. Its primary purpose is to mark any structure that requires it's `SType` field to be +correctly set when passing to Vulkan, and to provide a mechanism for doing so. # Contributors + - [Craig Dean, DevDecoder](https://github.com/thargy) # Current Status + - [x] Proposed - [ ] Discussed with API Review Board (ARB) - [ ] Approved - [ ] Implemented # Design Decisions -TODO + +- The `IStructuredType` interface will usually not be implemented directly, instead `IChainable` (from + the [unmanaged chaining proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md)) + will extend this interface. +- The BuildTools should instead only add this interface to any structure that meets the above constraints (the first + field must be `StructureType SType`) that _doesn't_ already add the `IChainable` interface. Though I believe this + scenario won't occur in the current Vulkan specification, I need to check all valid StructureType structures to + confirm, and regardless, writing the code to add the interface in such scenarios will future proof it. +- Whenever the `IStructuredType` is added to an interface + +# Implementation Notes + +- BuildTools already contains enough information to determine whether the interface should be added to a structure, and + already knows which `StructureType` the structure should use. +- A working example of such a struct can + be [found in the labs.](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs) # Proposed API -TODO \ No newline at end of file + +## StructureType structures + +### IStructuredType + +This proposal adds a single interface `IStructuredType`, the primary purpose of which is to mark any structure that +requires it's `SType` to be correctly set when passing to Vulkan. It adds a single +method `void IStructuredType.StructureType()` +which sets the `SType` correctly and returns it to the caller. + +```csharp +# ../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs +``` + +### IStructureType implementation + +Each struct generated that implements `IStructuredType` should also have the following code auto-generated, to +explicitly implement the interface. The method sets and returns the `SType` correctly for the current structure. + +```csharp +/// +StructureType IStructuredType.StructureType() +{ + return SType = StructureType.; +} +``` From 089f2e5406dc26269ef7533a99a2198bf7f690fc Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sat, 6 Nov 2021 18:08:09 +0000 Subject: [PATCH 21/34] docs: Embedded code sample directly into Proposal #1 --- ...Struct Chaining - #1 StructureType correction.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md index d114a75fe2..c05a802a0e 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md @@ -49,7 +49,18 @@ method `void IStructuredType.StructureType()` which sets the `SType` correctly and returns it to the caller. ```csharp -# ../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs +namespace Silk.Net.Vulkan; + +public interface IStructuredType +{ + /// + /// Gets the structured type's enum value. + /// + /// + /// Retrieving the also coerces it to the correct value. + /// + StructureType StructureType(); +} ``` ### IStructureType implementation From d5552b69fd54b258e2b350eb9776cf360af2576a Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sun, 7 Nov 2021 12:05:44 +0000 Subject: [PATCH 22/34] docs: Updated the Unmanaged Chaining Proposal. --- ... Chaining - #1 StructureType correction.md | 27 +- ...Struct Chaining - #2 Unmanaged Chaining.md | 481 +++++++++++++++++- .../PrototypeStructChaining/Chain.cs | 18 +- .../ChainExtensions.cs | 60 +-- .../DeviceCreateInfo.cs | 3 +- .../PrototypeStructChaining/IChainable.cs | 4 +- .../PrototypeStructChaining/IExtendsChain.cs | 5 +- .../IStructuredType.cs | 6 +- .../PhysicalDeviceFeatures2.cs | 3 +- 9 files changed, 556 insertions(+), 51 deletions(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md index c05a802a0e..a1532210f5 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md @@ -1,7 +1,7 @@ # Summary This proposal is a minimal enhancement to [`Silk.Net.Vulkan`](../../src/Vulkan/Silk.NET.Vulkan) to mark all structures -that contain a `StructureType SType` field (in the first position) as implementing the interface `IStructuredType`. +that contain a `StructureType SType` field as implementing the interface `IStructuredType`. This is a tiny pre-requisite for [Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) @@ -24,11 +24,22 @@ correctly set when passing to Vulkan, and to provide a mechanism for doing so. - The `IStructuredType` interface will usually not be implemented directly, instead `IChainable` (from the [unmanaged chaining proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md)) will extend this interface. -- The BuildTools should instead only add this interface to any structure that meets the above constraints (the first - field must be `StructureType SType`) that _doesn't_ already add the `IChainable` interface. Though I believe this - scenario won't occur in the current Vulkan specification, I need to check all valid StructureType structures to +- The BuildTools should instead only add this interface to any structure that meets the above constraint (the structure + has a `StructureType SType` field) that _doesn't_ already add the `IChainable` interface. Though I believe this + scenario won't occur in the current Vulkan specification, we'd need to check all valid StructureType structures to confirm, and regardless, writing the code to add the interface in such scenarios will future proof it. -- Whenever the `IStructuredType` is added to an interface +- Whenever the `IStructuredType` is added to an interface (either directly or indirectly) the + corresponding `StructureType()` method should also be explicitly + implemented ([see below](#istructuretype-implementation)). +- This proposed interface could easily be combined/merged with the `IChainable` + interface which [is proposed](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) as an + extension. However, that interface marks a struct as having a second field `void* PNext`, as well as requiring + that `StructureType sType` field is in the first position, which is not required by this proposal (but is allowed). + Keeping the two concepts separate is good encapsulation and good for supporting future changes. The concept + that an `SType` must be correct is somewhat different to the concept of a chain (implied by `void* PNext`). +- To be clear, this proposal does not need to guarantee that the `SType` field is in position 0 (i.e. first), + that requirement is only necessary to implement the functionality + [proposed by the unmanaged chaining system](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) # Implementation Notes @@ -51,13 +62,17 @@ which sets the `SType` correctly and returns it to the caller. ```csharp namespace Silk.Net.Vulkan; +/// +/// Base interface for any struct that has a field called `SType`, that must be correctly +/// set when passing into the Vulkan API. +/// public interface IStructuredType { /// /// Gets the structured type's enum value. /// /// - /// Retrieving the also coerces it to the correct value. + /// Retrieving the also ensures it is set to the correct value. /// StructureType StructureType(); } diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md index 6039b01fcd..baf8f809b6 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md @@ -1,17 +1,492 @@ # Summary -TODO + +This proposal presents a lightweight mechanism for fluently building Vulkan Structure Chains. You may wish to start with +the [Usage section below](#Usage) to aid understanding. There is also a fully working prototype +[in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/). + +To do so it marks any structure that meets the following requirements as being `IChainable`: + +* Is a struct. +* Has a `StructureType SType` field in position 0 (first field) +* Has a `void* PNext` field in position 1 (second field) + +The `IChainable` interface extends the `IStructuredType` interface +from [Proposal - Vulkan Struct Chaining - #1 StructureType correction](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md) +and so the explicit implementation of `IChainable.StructureType()` from +[that proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md#istructuretype-implementation) +is triggerred for the structure, providing a mechanism for ensuring the `SType` is correctly set. + +The presence of the `IChainable` interface, also acts as a **guarantee** that it is safe to cast any pointer of a struct +implementing it to a pointer to a `Chain` struct, which is a struct which has just the `SType` and `PNext` fields +present. Therefore it is always possible to cast `void* PNext` of an `IChainable` struct to `Chain*`. It is this +guarantee that requires the position of the fields to be fixed (which they are in practice). However, by ensuring we +validate the constraints at build time (when choosing to add the interface), we can prevent downstream bugs occurring at +run time. + +**Note** that the `IChainable` interface adds the additional constraint that the `StructureType SType` field must be at +offset 0, i.e. in the first position. + +However, rather than extending `IChainable` directly, it will be more common to choose one of `IChainStart` +or `IExtendsChain` (both of which extend `IChainable`). It does this based on the `structextends` attribute +provided in +the [Vulkan Specification](https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/registry/vk.xml)). + +For example, if `struct B` extends `struct A` (as per +the [Vulkan Specification](https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/registry/vk.xml)), then +`struct B` will be marked with `IExtendsChain` and `struct A` will be marked with `IChainStart`. A struct may only +extend `IChainStart` once (even though it may appear in the `structextends` attribute of many structs), but is may +implement multiple `IExtendsChain` interfaces. It is also feasible for a struct to implement both (i.e. be able +to extend other chains, as well as being a chain start), a real example of this can be seen +[in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs). + +As a result, `IChainable` will not usually be directly implemented (just as it is unlikely to see `IStructuredType` +[implemented directly]((Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md))). +However, if +the [Vulkan Specification](https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/registry/vk.xml) ever +includes a struct that meets the above constraints, but doesn't have, or appear in, a `structsextend` attribute, then it +will be explicitly marked as `IChainable`. + +Whenever a struct is marked as `IChainStart` a static `ref [StructType] Chain(out [StructType]) capture);` method is +also added, providing an easy form of starting a chain with default values. As `IChainStart` also +implements `IStructuredType` (via `IChainable`), then a chain start will have two additional methods generated (the +static +`Chain(out)` method and the explicit `IStructuredType.StructureType()` implementation); as compared to all other +`IChainable` structs, which will only have the explicit `IStructuredType.StructureType()` implementation from +[Proposal - Vulkan Struct Chaining - #1 StructureType correction](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md) +. + +The remaining functionality is provided entirely by the following new extension methods: + +```csharp +public static unsafe ref TChain SetNext(this ref TChain chain, ref TNext value, + bool alwaysAdd = false) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain {...} + +public static unsafe ref TChain AddNext(this ref TChain chain, out TNext next) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain {...} + +public static unsafe ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain {...} + +public static unsafe int IndexOf(this ref TChain chain, ref TNext value) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain {...} +``` + +Their implementation can be +found [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs) and +their use is detailed below. + +These extension methods # Contributors + - [Craig Dean, DevDecoder](https://github.com/thargy) # Current Status + - [x] Proposed - [ ] Discussed with API Review Board (ARB) - [ ] Approved - [ ] Implemented # Design Decisions -TODO + +The following requirements are achieved by this proposal: + +- **Backward compatibility** - the chaining system should not modify the existing structs, but add functionality. +- **Minimal bloat** - the minimum amount of new generated code was sought. +- **Discoverability** - it should be as easy as possible for a new user to discover. +- **Compile-time Validation** - it should prevent chaining invalid structures (as much as possible) during compilation. +- **SType coercion** - it should always set the `SType` of chained structures. +- **Pointer management** - it should handle setting the `PNext` pointer of structures. +- **Compact usage** - it should reduce copy-pasta code. +- **Avoids the heap** - boxing should be avoided. +- **Well Tested** - tests were added to ensure pointers are correctly set, and compilation failures occur. + +What this proposal does not do (some of these _are_ addressed +in [Proposal - Vulkan Struct Chaining - #3 Managed Chaining](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%233%20Managed%20Chaining.md)) +is manage pointers of structures that find themselves on the heap. Any supplied structures should be held on the stack, +once moved to the heap their `PNext` values can no longer be trusted as the GC is free to move structures in heap +memory. The interface of this proposal makes it difficult to use with heap objects, but it is not impossible. The +presence of the `ManagedChain` classes +from [the proposal for managed chains](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%233%20Managed%20Chaining.md), +along with a well documented API should highlight the danger of such practices. + +Indeed, it is important to remember that such dangers are already part of the existing implementation are a feature of +using unmanaged pointers in .NET rather than a 'limitation' of this proposal. + +# Usage + +The proposal provides for the following usage patterns: + +### Chain Building + +You can happily create the start of a chain as usual, and it's `SType` will be coerced when you start using it as a +chain: + +```csharp +var createInfo = new DeviceCreateInfo +{ + Flags = 1U +}; +// When you call any chaining method it will set the chain's SType automatically. +createinfo.AddNext... +``` + +-in many cases, we only want to create a default structure for population by the API. To do so, we use the +static `Chain` method like so: + +```csharp +PhysicalDeviceFeatures2.Chain(out var features2) +``` + +This has several advantages: + +- The method is only available for structures that are valid at the start of a chain; providing compile-time validation. +- The structure's `SType` will be correctly set immediately. +- The syntax is fluent, and creates more readable code when used with the other chaining methods (see below). + +**Note** All the chaining methods return the current start of the chain by reference (including `Chain`). This allows +each method to scan the entire chain. More importantly, it allows the Type constraints to be checked during compile time +to ensure that a type actually extends the chain. One side effect is that `ref Chain(out)` outputs the newly created +chain _and_ returns a reference to it. This can cause confusion to less experienced C# devs, for example: + +```csharp +// Don't do this, it is harmless but unnecessary and confusing! +var a = ChainStart.Chain(out var b).AddNext(out ChainExtension c); +``` + +Both `a` and `b` will appear to be identical structures; however 'a' is actually a copy of 'b', being separate locations +on the current stack frame. In most cases, that is really no problem at all as both point to the _start_ of a chain, and +so there are no unmanaged pointers pointing _to them_, therefore using _either_ is fine (though completely unnecessary). + +However, for deeper understanding the chain extension methods actually _take a reference_ to `this`, so `AddNext` +actually updates the `PNext` of variable `b`. Once the chain is built the final assignment _to_ `a` _copies_ `b` +into `a`. None of this is undefined behaviour, but as it is generally poorly understood so none of the examples ever +recommend assigning the output of a chain. + +### AddNext + +The most common use case is to add an empty structure to the end of a chain for it to be populated by the Vulkan API, +this can now be done like so: + +```csharp +PhysicalDeviceFeatures2 + .Chain(out var features2) + // CreateNext will create an empty struct, with the correct SType (as well as ensuring the + // chain's SType is set correctly). + .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); +``` + +Each method `out` puts a struct into the local stack frame for querying once populated, and the pointers point to this +local variable. Despite generics and interfaces being used, the chain methods avoid the heap entirely. + +### TryAddNext + +You may only want to add a structure if it doesn't already exist in the chain, this can be done with `TryAddNext`, e.g.: + +```csharp +PhysicalDeviceFeatures2 + .Chain(out var features2) + .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + // As there is already a PhysicalDeviceDescriptorIndexingFeatures structure the following + // will not add anything to the chain and `added` will be `false`. + .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures2, out bool added); +``` + +### SetNext + +Sometimes we may wish to set the initial state of a structure, or replace any existing item within the structure that +has the same `StructureType` we can do this with `SetNext`: + +```csharp +var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures +{ + ShaderInputAttachmentArrayDynamicIndexing = true +}; + +// Unlike AddNext, SetNext will only add the structure if isn't already present, otherwise it will overwrite it. +// So we can provide a default to SetNext like so: +var accelerationStructureFeaturesKhr = default(PhysicalDeviceAccelerationStructureFeaturesKHR); + +PhysicalDeviceFeatures2 + .Chain(out var features2) + // SetNext accepts an existing struct, note, it will coerce the SType and blank the PNext + .SetNext(ref indexingFeatures) + .SetNext(ref default(PhysicalDeviceAccelerationStructureFeaturesKHR)); +``` + +*NOTE* you can mix and match `AddNext` and `SetNext` (and any chaining method) in the same method chain. + +By default, `SetNext` will _replace_ any item in the chain with a matching `SType`, this behaviour can be changed by +setting the optional `alwaysAdd` parameter to `true`; + +```csharp +var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures +{ + ShaderInputAttachmentArrayDynamicIndexing = true +}; +var indexingFeatures2 = new PhysicalDeviceDescriptorIndexingFeatures +{ + ShaderInputAttachmentArrayDynamicIndexing = false +}; +var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKHR +{ + AccelerationStructure = true +}; + +PhysicalDeviceFeatures2 + .Chain(out var features2) + .SetNext(ref indexingFeatures) + // This will add the second 'indexingFeatures' struct, even though one is already present in the chain. + .SetNext(ref indexingFeatures2, true); +``` + +### IndexOf + +Sometimes it's useful to know if a structure you previously supplied is still in a chain, this can be done +with `IndexOf`, which returns a non-negative index (zero-indexed) if the structure is found, eg.: + +```csharp +PhysicalDeviceFeatures2 + .Chain(out var features2) + .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + +// Check indices +Assert.Equal(1, features2.IndexOf(ref indexingFeatures)); +Assert.Equal(2, features2.IndexOf(ref accelerationStructureFeaturesKhr)); +``` + +### Validation + +Due to the generic constraints, all the chain extensions are only valid on a struct that implements `IChainStart` and +only accept struct that implement `IExtends` where `TChain` is the chain type. This means that it is impossible +to add invalid structs to a chain with these methods. Further, using any of the chain extension methods guarantees that +the chain, and the supplied item have the correct `SType`, **and** that the `PNext` pointers along the chain are valid. # Proposed API -TODO \ No newline at end of file + +## Chaining interfaces + +### IChainable + +The base interface of chaining interfaces: + +```csharp +namespace Silk.Net.Vulkan; + +/// +/// Base interface for any struct that has can set the next value. +/// +/// Note that any structure marked must start with a +/// and a void* field, in that order. This is so that a pointer to it can be coerced +/// to a pointer to a . +public interface IChainable : IStructuredType +{ +} + +``` + +### IChainStart + +Implemented by any struct that can be used as the start of a chain: + +```csharp +namespace Silk.Net.Vulkan; + +/// +/// Marks a chainable struct as being allowed at the start of a chain. +/// +/// Any will have a corresponding static `Chain(out var chain)` +/// convenience method. +public interface IChainStart : IChainable +{ +} +``` + +### IExtendsChain + +Implemented by any struct that can be added to a chain. + +```csharp +namespace Silk.Net.Vulkan; + +/// +/// Marks a chainable struct indicating which chain this type +/// extends. +/// +/// A chain start structure. +public interface IExtendsChain : IChainable + where TChain : IChainable +{ +} +``` + +### Chain Extensions + +Provides the struct chaining functionality, the full implementation can be +found [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs): + +```csharp +namespace Silk.Net.Vulkan; + +public static class ChainExtensions +{ + /// + /// Replaces a structure in the chain (if present, and is false), or adds it to the end. + /// + /// The current chain + /// A reference to the structure to update + /// Always adds to the end of the chain, even if an equivalent structure is present. + /// The type of the current chain + /// The type of the value + /// A reference to the value value in the chain + /// + /// Note that both the supplied chain, and the supplied value will have their `SType` correctly set. Further, + /// the supplied structure's will be overwritten. + /// To use + /// + /// var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + /// { + /// ShaderInputAttachmentArrayDynamicIndexing = true + /// }; + /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKHR + /// { + /// AccelerationStructure = true + /// }; + /// + /// PhysicalDeviceFeatures2 + /// .Chain(out var features2) + /// .SetNext(ref indexingFeatures) + /// .SetNext(ref accelerationStructureFeaturesKhr); + /// + /// + public static unsafe ref TChain SetNext(this ref TChain chain, ref TNext value, + bool alwaysAdd = false) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain {...} + + /// + /// Adds a structure to the end of the chain. + /// + /// The current chain + /// The structure added to the end of the chain + /// The type of the current chain + /// The type of the structure to add + /// The reference to the chain. + /// + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .Chain(out var features2) + /// .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + /// + /// Note, the value is always added, even if an equivalent value is added in the chain already. Use + /// to only add if not already present. + /// + public static unsafe ref TChain AddNext(this ref TChain chain, out TNext next) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain {...} + + /// + /// Tries to add a structure to the end of the chain. + /// + /// The current chain + /// The structure added to the end of the chain + /// Whether the structure was actually added + /// The type of the current chain + /// The type of the structure to add + /// The reference to the chain. + /// + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .Chain(out var features2) + /// .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures, out var added); + /// + /// + public static unsafe ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain {...} + + /// + /// Returns the index of the in the , if present. + /// + /// The chain + /// The structure value + /// The type of the current chain + /// The type of the value + /// The zero-indexed index if found; otherwise -1. + public static unsafe int IndexOf(this ref TChain chain, ref TNext value) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain {...} +} +``` + +### Chain Structure + +The `Chain` struct makes it easy to access the `SType` and `PNext` of a structure pointed to by `void* PNext`, although +it is used internally, it is useful for consumers of Silk.Net to have access to use in their own scenarios, that is +because the `IChainable` interface does not directly expose the underlying `SType` and `PNext` fields; as they are +fields (not properties), and this proposal aims to avoid boxing (so we try not to use the interface directly +unnecessarily). + +```csharp +namespace Silk.Net.Vulkan; + +/// +/// Header struct of all structs. +/// +/// +/// Any pointer to a structure marked as can safely be cast to a pointer to this type. +/// In particular, this means that the void* PNext field can always be safely cast to Chain*, providing +/// access to the `SType` and `PNext` fields. +/// +/// +public struct Chain : IChainable +{ + /// + /// The structure type. + /// + public StructureType SType; + /// + /// The next struct in the chain, if any; otherwise . + /// + public unsafe Chain* PNext; + + /// + /// Note, this cannot coerce the type as 'guaranteed by the `IStructuredType` interface. + StructureType IStructuredType.StructureType() + { + return SType; + } +} +``` + +### Static Chain implementation + +Whenever the `IChainStart` interface is added to an `IChainable` struct, the following static convenience methods is +also added: + +```csharp +/// +/// Convenience method to start a chain. +/// +/// The newly created chain root +/// A reference to the newly created chain. +public static unsafe ref [StrucType] Chain( + out [StructType] capture) +{ + capture = new [StructType](StructureType.[StructureType]); + return ref capture; +} +``` diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs index 5f0ff03b0f..78984e2678 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs @@ -1,17 +1,29 @@ namespace Silk.Net.Vulkan; /// -/// Header struct of all chainable structs. +/// Header struct of all structs. /// +/// +/// Any pointer to a structure marked as can safely be cast to a pointer to this type. +/// In particular, this means that the void* PNext field can always be safely cast to Chain*, providing +/// access to the `SType` and `PNext` fields. +/// +/// public struct Chain : IChainable { + /// + /// The structure type. + /// public StructureType SType; + /// + /// The next struct in the chain, if any; otherwise . + /// public unsafe Chain* PNext; /// - /// Note, this doesn't coerce the type. + /// Note, this cannot coerce the type as 'guaranteed by the `IStructuredType` interface. StructureType IStructuredType.StructureType() { return SType; } -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs index d0b5d95fef..4c0bf8ebde 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs @@ -69,36 +69,6 @@ public static unsafe ref TChain SetNext(this ref TChain chain, re return ref chain; } - /// - /// Returns the index of the in the , if present. - /// - /// The chain - /// The structure value - /// The type of the current chain - /// The type of the value - /// The zero-indexed index if found; otherwise -1. - public static unsafe int IndexOf(this ref TChain chain, ref TNext value) - where TChain : struct, IChainStart - where TNext : struct, IExtendsChain - { - // Ensure structure type of chain is set. - chain.StructureType(); - - var index = 0; - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - var valuePtr = (Chain*) Unsafe.AsPointer(ref value); - // Follow chain - do - { - if (currentPtr == valuePtr) - return index; - currentPtr = currentPtr->PNext; - index++; - } while (currentPtr is not null); - - return -1; - } - /// /// Adds a structure to the end of the chain. /// @@ -185,4 +155,34 @@ public static unsafe ref TChain TryAddNext(this ref TChain chain, added = true; return ref chain; } + + /// + /// Returns the index of the in the , if present. + /// + /// The chain + /// The structure value + /// The type of the current chain + /// The type of the value + /// The zero-indexed index if found; otherwise -1. + public static unsafe int IndexOf(this ref TChain chain, ref TNext value) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain + { + // Ensure structure type of chain is set. + chain.StructureType(); + + var index = 0; + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + var valuePtr = (Chain*) Unsafe.AsPointer(ref value); + // Follow chain + do + { + if (currentPtr == valuePtr) + return index; + currentPtr = currentPtr->PNext; + index++; + } while (currentPtr is not null); + + return -1; + } } \ No newline at end of file diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs index 4f7712d6e6..d6f477d8cb 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs @@ -39,8 +39,7 @@ public unsafe DeviceCreateInfo( public static unsafe ref DeviceCreateInfo Chain( out DeviceCreateInfo capture) { - capture = new DeviceCreateInfo( - StructureType.DeviceCreateInfo); + capture = new DeviceCreateInfo(StructureType.DeviceCreateInfo); return ref capture; } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs index f33553d72c..7b8df844f2 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs @@ -4,8 +4,8 @@ namespace Silk.Net.Vulkan; /// Base interface for any struct that has can set the next value. /// /// Note that any structure marked must start with a -/// and a void* field. So that a pointer to it can be coerced +/// and a void* field, in that order. This is so that a pointer to it can be coerced /// to a pointer to a . public interface IChainable : IStructuredType { -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IExtendsChain.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IExtendsChain.cs index 360c2063c8..5ef0a4ad99 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IExtendsChain.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IExtendsChain.cs @@ -1,10 +1,11 @@ namespace Silk.Net.Vulkan; /// -/// Generic interface indicating which chain this type can be added to. +/// Marks a chainable struct indicating which chain this type +/// extends. /// /// A chain start structure. public interface IExtendsChain : IChainable where TChain : IChainable { -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs index 79d9385017..aa6a7fdbc1 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs @@ -1,12 +1,16 @@ namespace Silk.Net.Vulkan; +/// +/// Base interface for any struct that has a field called `SType`, that must be correctly +/// set when passing into the Vulkan API. +/// public interface IStructuredType { /// /// Gets the structured type's enum value. /// /// - /// Retrieving the also coerces it to the correct value. + /// Retrieving the also ensures it is set to the correct value. /// StructureType StructureType(); } \ No newline at end of file diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs index 8db163f074..f9aae21d47 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs @@ -33,8 +33,7 @@ public unsafe PhysicalDeviceFeatures2( public static unsafe ref PhysicalDeviceFeatures2 Chain( out PhysicalDeviceFeatures2 capture) { - capture = new PhysicalDeviceFeatures2( - StructureType.PhysicalDeviceFeatures2); + capture = new PhysicalDeviceFeatures2(StructureType.PhysicalDeviceFeatures2); return ref capture; } From bd9f0eb0c1647622c012ea024b26159f24d593a9 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sun, 7 Nov 2021 12:08:49 +0000 Subject: [PATCH 23/34] chore: Minor fixes to lab * Restored targets for PrototypeStructChaining.csproj to match `Silk.Net.Vulkan` targets. * Upped the generated `ManageChain Load( return new(out var _, chain); } + /// + /// Creates a new with 6 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// A new with 6 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5); + } + + /// + /// Loads a new with 6 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 6 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 6 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 6 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 7 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// A new with 7 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6); + } + + /// + /// Loads a new with 7 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 7 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 7 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 7 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 8 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// A new with 8 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7); + } + + /// + /// Loads a new with 8 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 8 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 8 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 8 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 9 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// A new with 9 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8); + } + + /// + /// Loads a new with 9 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 9 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 9 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 9 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 10 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// A new with 10 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9); + } + + /// + /// Loads a new with 10 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 10 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 10 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 10 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 11 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// A new with 11 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10); + } + + /// + /// Loads a new with 11 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 11 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 11 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 11 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 12 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// A new with 12 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11); + } + + /// + /// Loads a new with 12 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 12 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 12 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 12 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 13 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// A new with 13 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12); + } + + /// + /// Loads a new with 13 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 13 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 13 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 13 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 14 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// A new with 14 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); + } + + /// + /// Loads a new with 14 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 14 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 14 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 14 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 15 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// A new with 15 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); + } + + /// + /// Loads a new with 15 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 15 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 15 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 15 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + { + return new(out var _, chain); + } + + /// + /// Creates a new with 16 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// Item 15. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. + /// A new with 16 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + { + return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); + } + + /// + /// Loads a new with 16 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 16 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + { + return new(out errors, chain); + } + + /// + /// Loads a new with 16 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 16 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + { + return new(out var _, chain); + } + +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 2 items. + /// + /// The head of the chain. + /// Item 1. + public ManagedChain(TChain head = default, T1 item1 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + } + + /// + /// Creates a new with 2 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); + } + var item1Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + } + + /// + /// Creates a new with 3 items, by appending to + /// the end of this chain. + /// + /// Item 2. + /// Type of Item 2 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T2 item2 = default) + where T2: struct, IExtendsChain + { + return new ManagedChain(this, item2); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + } + + /// + public override int Count => 2; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + public void Deconstruct(out TChain head, out T1 item1) + { + head = Head; + item1 = Item1; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + } + + /// + /// Creates a new with 3 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 3"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 3"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 3"); + } + var item2Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + } + + /// + /// Creates a new with 3 items. + /// + /// The chain to append to. + /// Item 2. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T2 item2 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size; + var newSize = originalSize + item2Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + // Append the last structure + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + } + + /// + /// Creates a new with 4 items, by appending to + /// the end of this chain. + /// + /// Item 3. + /// Type of Item 3 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T3 item3 = default) + where T3: struct, IExtendsChain + { + return new ManagedChain(this, item3); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + } + + /// + public override int Count => 3; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2) + { + head = Head; + item1 = Item1; + item2 = Item2; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 4 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + } + + /// + /// Creates a new with 4 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 4"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 4"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 4"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 4"); + } + var item3Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + } + + /// + /// Creates a new with 4 items. + /// + /// The chain to append to. + /// Item 3. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T3 item3 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size; + var newSize = originalSize + item3Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + // Append the last structure + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + } + + /// + /// Creates a new with 5 items, by appending to + /// the end of this chain. + /// + /// Item 4. + /// Type of Item 4 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T4 item4 = default) + where T4: struct, IExtendsChain + { + return new ManagedChain(this, item4); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + } + + /// + public override int Count => 4; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 5 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + } + + /// + /// Creates a new with 5 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 5"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 5"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 5"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 5"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 5"); + } + var item4Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + } + + /// + /// Creates a new with 5 items. + /// + /// The chain to append to. + /// Item 4. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T4 item4 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size; + var newSize = originalSize + item4Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + // Append the last structure + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + } + + /// + /// Creates a new with 6 items, by appending to + /// the end of this chain. + /// + /// Item 5. + /// Type of Item 5 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T5 item5 = default) + where T5: struct, IExtendsChain + { + return new ManagedChain(this, item5); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + } + + /// + public override int Count => 5; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 6 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + } + + /// + /// Creates a new with 6 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 6"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 6"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 6"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 6"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 6"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 6"); + } + var item5Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + } + + /// + /// Creates a new with 6 items. + /// + /// The chain to append to. + /// Item 5. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T5 item5 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size; + var newSize = originalSize + item5Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + // Append the last structure + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + } + + /// + /// Creates a new with 7 items, by appending to + /// the end of this chain. + /// + /// Item 6. + /// Type of Item 6 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T6 item6 = default) + where T6: struct, IExtendsChain + { + return new ManagedChain(this, item6); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + } + + /// + public override int Count => 6; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 7 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + } + + /// + /// Creates a new with 7 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 7"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 7"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 7"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 7"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 7"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 7"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 7"); + } + var item6Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + } + + /// + /// Creates a new with 7 items. + /// + /// The chain to append to. + /// Item 6. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T6 item6 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size; + var newSize = originalSize + item6Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + // Append the last structure + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + } + + /// + /// Creates a new with 8 items, by appending to + /// the end of this chain. + /// + /// Item 7. + /// Type of Item 7 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T7 item7 = default) + where T7: struct, IExtendsChain + { + return new ManagedChain(this, item7); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + } + + /// + public override int Count => 7; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 8 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + } + + /// + /// Creates a new with 8 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 8"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 8"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 8"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 8"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 8"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 8"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 8"); + else { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item7 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 8"); + } + var item7Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + } + + /// + /// Creates a new with 8 items. + /// + /// The chain to append to. + /// Item 7. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T7 item7 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size; + var newSize = originalSize + item7Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + // Append the last structure + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + } + + /// + /// Creates a new with 9 items, by appending to + /// the end of this chain. + /// + /// Item 8. + /// Type of Item 8 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T8 item8 = default) + where T8: struct, IExtendsChain + { + return new ManagedChain(this, item8); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + } + + /// + public override int Count => 8; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 9 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + } + + /// + /// Creates a new with 9 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 9"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 9"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 9"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 9"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 9"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 9"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 9"); + else { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item7 = Unsafe.AsRef(currentPtr); + } + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 9"); + else { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item8 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 9"); + } + var item8Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + } + + /// + /// Creates a new with 9 items. + /// + /// The chain to append to. + /// Item 8. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T8 item8 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size; + var newSize = originalSize + item8Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + // Append the last structure + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + } + + /// + /// Creates a new with 10 items, by appending to + /// the end of this chain. + /// + /// Item 9. + /// Type of Item 9 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T9 item9 = default) + where T9: struct, IExtendsChain + { + return new ManagedChain(this, item9); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + yield return Item8; + } + + /// + public override int Count => 9; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + 8 => Item8, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + item8 = Item8; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 10 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + } + + /// + /// Creates a new with 10 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 10"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 10"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 10"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 10"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 10"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 10"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 10"); + else { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item7 = Unsafe.AsRef(currentPtr); + } + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 10"); + else { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item8 = Unsafe.AsRef(currentPtr); + } + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 10"); + else { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item9 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 10"); + } + var item9Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + } + + /// + /// Creates a new with 10 items. + /// + /// The chain to append to. + /// Item 9. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T9 item9 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size; + var newSize = originalSize + item9Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + // Append the last structure + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + } + + /// + /// Creates a new with 11 items, by appending to + /// the end of this chain. + /// + /// Item 10. + /// Type of Item 10 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T10 item10 = default) + where T10: struct, IExtendsChain + { + return new ManagedChain(this, item10); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + yield return Item8; + yield return Item9; + } + + /// + public override int Count => 10; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + 8 => Item8, + 9 => Item9, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + item8 = Item8; + item9 = Item9; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 11 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + } + + /// + /// Creates a new with 11 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 11"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 11"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 11"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 11"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 11"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 11"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 11"); + else { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item7 = Unsafe.AsRef(currentPtr); + } + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 11"); + else { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item8 = Unsafe.AsRef(currentPtr); + } + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 11"); + else { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item9 = Unsafe.AsRef(currentPtr); + } + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 11"); + else { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item10 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 11"); + } + var item10Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + } + + /// + /// Creates a new with 11 items. + /// + /// The chain to append to. + /// Item 10. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T10 item10 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size; + var newSize = originalSize + item10Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + // Append the last structure + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + } + + /// + /// Creates a new with 12 items, by appending to + /// the end of this chain. + /// + /// Item 11. + /// Type of Item 11 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T11 item11 = default) + where T11: struct, IExtendsChain + { + return new ManagedChain(this, item11); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + yield return Item8; + yield return Item9; + yield return Item10; + } + + /// + public override int Count => 11; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + 8 => Item8, + 9 => Item9, + 10 => Item10, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + item8 = Item8; + item9 = Item9; + item10 = Item10; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + private IntPtr _item11Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item11Ptr => (Chain*) _item11Ptr; + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef((Chain*) _item11Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 12 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + } + + /// + /// Creates a new with 12 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 12"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 12"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 12"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 12"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 12"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 12"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 12"); + else { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item7 = Unsafe.AsRef(currentPtr); + } + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 12"); + else { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item8 = Unsafe.AsRef(currentPtr); + } + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 12"); + else { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item9 = Unsafe.AsRef(currentPtr); + } + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 12"); + else { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item10 = Unsafe.AsRef(currentPtr); + } + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 12"); + else { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item11 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 12"); + } + var item11Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + } + + /// + /// Creates a new with 12 items. + /// + /// The chain to append to. + /// Item 11. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T11 item11 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size; + var newSize = originalSize + item11Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + // Append the last structure + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + } + + /// + /// Creates a new with 13 items, by appending to + /// the end of this chain. + /// + /// Item 12. + /// Type of Item 12 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T12 item12 = default) + where T12: struct, IExtendsChain + { + return new ManagedChain(this, item12); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + yield return Item8; + yield return Item9; + yield return Item10; + yield return Item11; + } + + /// + public override int Count => 12; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + 8 => Item8, + 9 => Item9, + 10 => Item10, + 11 => Item11, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10, out T11 item11) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + item8 = Item8; + item9 = Item9; + item10 = Item10; + item11 = Item11; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + private IntPtr _item11Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item11Ptr => (Chain*) _item11Ptr; + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef((Chain*) _item11Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; + } + } + private IntPtr _item12Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item12Ptr => (Chain*) _item12Ptr; + + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef((Chain*) _item12Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item12Ptr)->PNext; + Marshal.StructureToPtr(value, _item12Ptr, true); + ((Chain*) _item12Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 13 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + } + + /// + /// Creates a new with 13 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 13"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 13"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 13"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 13"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 13"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 13"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 13"); + else { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item7 = Unsafe.AsRef(currentPtr); + } + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 13"); + else { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item8 = Unsafe.AsRef(currentPtr); + } + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 13"); + else { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item9 = Unsafe.AsRef(currentPtr); + } + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 13"); + else { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item10 = Unsafe.AsRef(currentPtr); + } + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 13"); + else { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item11 = Unsafe.AsRef(currentPtr); + } + var item11Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T12 item12 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 13"); + else { + expectedStructureType = item12.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item12 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 13"); + } + var item12Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + } + + /// + /// Creates a new with 13 items. + /// + /// The chain to append to. + /// Item 12. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T12 item12 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size; + var newSize = originalSize + item12Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + // Append the last structure + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + } + + /// + /// Creates a new with 14 items, by appending to + /// the end of this chain. + /// + /// Item 13. + /// Type of Item 13 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T13 item13 = default) + where T13: struct, IExtendsChain + { + return new ManagedChain(this, item13); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + yield return Item8; + yield return Item9; + yield return Item10; + yield return Item11; + yield return Item12; + } + + /// + public override int Count => 13; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + 8 => Item8, + 9 => Item9, + 10 => Item10, + 11 => Item11, + 12 => Item12, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10, out T11 item11, out T12 item12) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + item8 = Item8; + item9 = Item9; + item10 = Item10; + item11 = Item11; + item12 = Item12; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item12Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +/// Type of Item 13. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + private IntPtr _item2Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) _item2Ptr; + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; + } + } + private IntPtr _item3Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } + } + private IntPtr _item5Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } + } + private IntPtr _item6Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } + } + private IntPtr _item7Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + private IntPtr _item11Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item11Ptr => (Chain*) _item11Ptr; + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef((Chain*) _item11Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; + } + } + private IntPtr _item12Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item12Ptr => (Chain*) _item12Ptr; + + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef((Chain*) _item12Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item12Ptr)->PNext; + Marshal.StructureToPtr(value, _item12Ptr, true); + ((Chain*) _item12Ptr)->PNext = nextPtr; + } + } + private IntPtr _item13Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item13Ptr => (Chain*) _item13Ptr; + + /// + /// Gets or sets item #13 in the chain. + /// + public T13 Item13 + { + get => Unsafe.AsRef((Chain*) _item13Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item13Ptr)->PNext; + Marshal.StructureToPtr(value, _item13Ptr, true); + ((Chain*) _item13Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 14 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + item2.StructureType(); + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + item13.StructureType(); + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + } + + /// + /// Creates a new with 14 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 14"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + } + var item1Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T2 item2 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 14"); + else { + expectedStructureType = item2.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item2 = Unsafe.AsRef(currentPtr); + } + var item2Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 14"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 14"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 14"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 14"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 14"); + else { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item7 = Unsafe.AsRef(currentPtr); + } + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 14"); + else { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item8 = Unsafe.AsRef(currentPtr); + } + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 14"); + else { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item9 = Unsafe.AsRef(currentPtr); + } + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 14"); + else { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item10 = Unsafe.AsRef(currentPtr); + } + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 14"); + else { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item11 = Unsafe.AsRef(currentPtr); + } + var item11Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T12 item12 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 14"); + else { + expectedStructureType = item12.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item12 = Unsafe.AsRef(currentPtr); + } + var item12Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T13 item13 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 14"); + else { + expectedStructureType = item13.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 14; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item13 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 14"); + } + var item13Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item2, _item2Ptr, false); + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + } + + /// + /// Creates a new with 14 items. + /// + /// The chain to append to. + /// Item 13. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T13 item13 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + var item2Size = Marshal.SizeOf(); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size; + var newSize = originalSize + item13Size; + + _headPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + + _item1Ptr = _headPtr + headSize; + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + + _item2Ptr = _item1Ptr + item1Size; + ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + // Append the last structure + item13.StructureType(); + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + } + + /// + /// Creates a new with 15 items, by appending to + /// the end of this chain. + /// + /// Item 14. + /// Type of Item 14 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T14 item14 = default) + where T14: struct, IExtendsChain + { + return new ManagedChain(this, item14); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + yield return Item8; + yield return Item9; + yield return Item10; + yield return Item11; + yield return Item12; + yield return Item13; + } + + /// + public override int Count => 14; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + 8 => Item8, + 9 => Item9, + 10 => Item10, + 11 => Item11, + 12 => Item12, + 13 => Item13, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10, out T11 item11, out T12 item12, out T13 item13) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + item8 = Item8; + item9 = Item9; + item10 = Item10; + item11 = Item11; + item12 = Item12; + item13 = Item13; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item12Ptr); + var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item13Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. -public unsafe class ManagedChain : ManagedChain +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +/// Type of Item 13. +/// Type of Item 14. +public unsafe class ManagedChain : ManagedChain where TChain : struct, IChainStart where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain { private IntPtr _headPtr; @@ -274,223 +8667,318 @@ public T1 Item1 ((Chain*) _item1Ptr)->PNext = nextPtr; } } + private IntPtr _item2Ptr; /// - /// Creates a new with 2 items. + /// Gets a pointer to the second item in the chain. /// - /// The head of the chain. - /// Item 1. - public ManagedChain(TChain head = default, T1 item1 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - } + public Chain* Item2Ptr => (Chain*) _item2Ptr; /// - /// Creates a new with 2 items from an existing unmanaged chain. + /// Gets or sets item #2 in the chain. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) + public T2 Item2 { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - StringBuilder errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); + get => Unsafe.AsRef((Chain*) _item2Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item2Ptr)->PNext; + Marshal.StructureToPtr(value, _item2Ptr, true); + ((Chain*) _item2Ptr)->PNext = nextPtr; } - var item1Size = Marshal.SizeOf(); + } + private IntPtr _item3Ptr; + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) _item3Ptr; - // Create string of errors - errors = errorBuilder.ToString().Trim(); + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef((Chain*) _item3Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item3Ptr)->PNext; + Marshal.StructureToPtr(value, _item3Ptr, true); + ((Chain*) _item3Ptr)->PNext = nextPtr; + } + } + private IntPtr _item4Ptr; - _headPtr = Marshal.AllocHGlobal(headSize + item1Size); - Marshal.StructureToPtr(head, _headPtr, false); + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item4Ptr => (Chain*) _item4Ptr; - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; + } } + private IntPtr _item5Ptr; /// - /// Creates a new with 3 items, by appending to - /// the end of this chain. + /// Gets a pointer to the second item in the chain. /// - /// Item 2. - /// Type of Item 2 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T2 item2 = default) - where T2: struct, IExtendsChain + public Chain* Item5Ptr => (Chain*) _item5Ptr; + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 { - return new ManagedChain(this, item2); + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; + } } + private IntPtr _item6Ptr; - /// - public override IEnumerator GetEnumerator() + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item6Ptr => (Chain*) _item6Ptr; + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 { - yield return Head; - yield return Item1; + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } } + private IntPtr _item7Ptr; - /// - public override int Count => 2; + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; - /// - public override IChainable this[int index] - => index switch + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef((Chain*) _item7Ptr); + set { - 0 => Head, 1 => Item1, - _ => throw new IndexOutOfRangeException() - }; + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } + } + private IntPtr _item8Ptr; /// - /// Deconstructs this chain. + /// Gets a pointer to the second item in the chain. /// - /// The head of the chain. - /// Item 1. - public void Deconstruct(out TChain head, out T1 item1) - { - head = Head; - item1 = Item1; - } + public Chain* Item8Ptr => (Chain*) _item8Ptr; - /// - public override void Dispose() + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + get => Unsafe.AsRef((Chain*) _item8Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item9Ptr => (Chain*) _item9Ptr; - // Free memory block - Marshal.FreeHGlobal(headPtr); + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } } -} + private IntPtr _item10Ptr; -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain -{ - private IntPtr _headPtr; + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } + } + private IntPtr _item11Ptr; /// - /// Gets a pointer to the current head. + /// Gets a pointer to the second item in the chain. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public Chain* Item11Ptr => (Chain*) _item11Ptr; /// - /// Gets or sets the head of the chain. + /// Gets or sets item #11 in the chain. /// - public TChain Head + public T11 Item11 { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((Chain*) _item11Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; } } + private IntPtr _item12Ptr; - private IntPtr _item1Ptr; + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item12Ptr => (Chain*) _item12Ptr; + + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef((Chain*) _item12Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item12Ptr)->PNext; + Marshal.StructureToPtr(value, _item12Ptr, true); + ((Chain*) _item12Ptr)->PNext = nextPtr; + } + } + private IntPtr _item13Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item13Ptr => (Chain*) _item13Ptr; /// - /// Gets or sets item #1 in the chain. + /// Gets or sets item #13 in the chain. /// - public T1 Item1 + public T13 Item13 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef((Chain*) _item13Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var nextPtr = ((Chain*) _item13Ptr)->PNext; + Marshal.StructureToPtr(value, _item13Ptr, true); + ((Chain*) _item13Ptr)->PNext = nextPtr; } } - private IntPtr _item2Ptr; + private IntPtr _item14Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item14Ptr => (Chain*) _item14Ptr; /// - /// Gets or sets item #2 in the chain. + /// Gets or sets item #14 in the chain. /// - public T2 Item2 + public T14 Item14 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef((Chain*) _item14Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var nextPtr = ((Chain*) _item14Ptr)->PNext; + Marshal.StructureToPtr(value, _item14Ptr, true); + ((Chain*) _item14Ptr)->PNext = nextPtr; } } /// - /// Creates a new with 3 items. + /// Creates a new with 15 items. /// /// The head of the chain. /// Item 1. /// Item 2. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default) + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); var item1Size = Marshal.SizeOf(); var item2Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size); + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + var item14Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -503,10 +8991,70 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul item2.StructureType(); Marshal.StructureToPtr(item2, _item2Ptr, false); ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + item3.StructureType(); + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + item4.StructureType(); + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + item13.StructureType(); + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + item14.StructureType(); + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; } /// - /// Creates a new with 3 items from an existing unmanaged chain. + /// Creates a new with 15 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. @@ -522,7 +9070,7 @@ public ManagedChain(out string errors, TChain chain) currentPtr = currentPtr->PNext; T1 item1 = default; if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 3"); + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 15"); else { expectedStructureType = item1.StructureType(); if (currentPtr->SType != expectedStructureType) { @@ -539,7 +9087,7 @@ public ManagedChain(out string errors, TChain chain) currentPtr = currentPtr->PNext; T2 item2 = default; if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 3"); + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 15"); else { expectedStructureType = item2.StructureType(); if (currentPtr->SType != expectedStructureType) { @@ -550,16 +9098,220 @@ public ManagedChain(out string errors, TChain chain) .AppendLine(); } else item2 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 3"); } var item2Size = Marshal.SizeOf(); + currentPtr = currentPtr->PNext; + T3 item3 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 15"); + else { + expectedStructureType = item3.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item3 = Unsafe.AsRef(currentPtr); + } + var item3Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T4 item4 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 15"); + else { + expectedStructureType = item4.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item4 = Unsafe.AsRef(currentPtr); + } + var item4Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 15"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 15"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 15"); + else { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item7 = Unsafe.AsRef(currentPtr); + } + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 15"); + else { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item8 = Unsafe.AsRef(currentPtr); + } + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 15"); + else { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item9 = Unsafe.AsRef(currentPtr); + } + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 15"); + else { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item10 = Unsafe.AsRef(currentPtr); + } + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 15"); + else { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item11 = Unsafe.AsRef(currentPtr); + } + var item11Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T12 item12 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 15"); + else { + expectedStructureType = item12.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item12 = Unsafe.AsRef(currentPtr); + } + var item12Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T13 item13 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 15"); + else { + expectedStructureType = item13.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 14; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item13 = Unsafe.AsRef(currentPtr); + } + var item13Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T14 item14 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 15"); + else { + expectedStructureType = item14.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 15; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item14 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 15"); + } + var item14Size = Marshal.SizeOf(); + // Create string of errors errors = errorBuilder.ToString().Trim(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size); Marshal.StructureToPtr(head, _headPtr, false); _item1Ptr = _headPtr + headSize; @@ -569,25 +9321,85 @@ public ManagedChain(out string errors, TChain chain) _item2Ptr = _item1Ptr + item1Size; Marshal.StructureToPtr(item2, _item2Ptr, false); ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item3, _item3Ptr, false); + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item4, _item4Ptr, false); + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; } /// - /// Creates a new with 3 items. + /// Creates a new with 15 items. /// /// The chain to append to. - /// Item 2. + /// Item 14. /// /// Do not forget to dispose the chain if you are no longer using it. /// - public ManagedChain(ManagedChain previous, T2 item2 = default) + public ManagedChain(ManagedChain previous, T14 item14 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); var item1Size = Marshal.SizeOf(); var item2Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size; - var newSize = originalSize + item2Size; + var item3Size = Marshal.SizeOf(); + var item4Size = Marshal.SizeOf(); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + var item14Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size; + var newSize = originalSize + item14Size; _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed @@ -597,25 +9409,61 @@ public ManagedChain(ManagedChain previous, T2 item2 = default) ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; _item2Ptr = _item1Ptr + item1Size; - // Append the last structure - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + + _item3Ptr = _item2Ptr + item2Size; + ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + + _item4Ptr = _item3Ptr + item3Size; + ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + // Append the last structure + item14.StructureType(); + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; } /// - /// Creates a new with 4 items, by appending to + /// Creates a new with 16 items, by appending to /// the end of this chain. /// - /// Item 3. - /// Type of Item 3 + /// Item 15. + /// Type of Item 15 /// /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain Append(T3 item3 = default) - where T3: struct, IExtendsChain + public ManagedChain Append(T15 item15 = default) + where T15: struct, IExtendsChain { - return new ManagedChain(this, item3); + return new ManagedChain(this, item15); } /// @@ -624,10 +9472,22 @@ public override IEnumerator GetEnumerator() yield return Head; yield return Item1; yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + yield return Item8; + yield return Item9; + yield return Item10; + yield return Item11; + yield return Item12; + yield return Item13; + yield return Item14; } /// - public override int Count => 3; + public override int Count => 15; /// public override IChainable this[int index] @@ -635,6 +9495,18 @@ public override IChainable this[int index] { 0 => Head, 1 => Item1, 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + 8 => Item8, + 9 => Item9, + 10 => Item10, + 11 => Item11, + 12 => Item12, + 13 => Item13, + 14 => Item14, _ => throw new IndexOutOfRangeException() }; @@ -644,11 +9516,35 @@ public override IChainable this[int index] /// The head of the chain. /// Item 1. /// Item 2. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2) + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10, out T11 item11, out T12 item12, out T13 item13, out T14 item14) { head = Head; item1 = Item1; item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + item8 = Item8; + item9 = Item9; + item10 = Item10; + item11 = Item11; + item12 = Item12; + item13 = Item13; + item14 = Item14; } /// @@ -663,6 +9559,30 @@ public override void Dispose() Marshal.DestroyStructure(item1Ptr); var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); Marshal.DestroyStructure(item2Ptr); + var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item3Ptr); + var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item12Ptr); + var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item13Ptr); + var item14Ptr = Interlocked.Exchange(ref _item14Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item14Ptr); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -670,17 +9590,41 @@ public override void Dispose() } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. /// Type of Item 2. /// Type of Item 3. -public unsafe class ManagedChain : ManagedChain +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +/// Type of Item 13. +/// Type of Item 14. +/// Type of Item 15. +public unsafe class ManagedChain : ManagedChain where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain { private IntPtr _headPtr; @@ -767,368 +9711,279 @@ public T3 Item3 ((Chain*) _item3Ptr)->PNext = nextPtr; } } + private IntPtr _item4Ptr; /// - /// Creates a new with 4 items. + /// Gets a pointer to the second item in the chain. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size); - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - } + public Chain* Item4Ptr => (Chain*) _item4Ptr; /// - /// Creates a new with 4 items from an existing unmanaged chain. + /// Gets or sets item #4 in the chain. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) + public T4 Item4 { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - StringBuilder errorBuilder = new StringBuilder(); - - currentPtr = currentPtr->PNext; - T1 item1 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 4"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + get => Unsafe.AsRef((Chain*) _item4Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item4Ptr)->PNext; + Marshal.StructureToPtr(value, _item4Ptr, true); + ((Chain*) _item4Ptr)->PNext = nextPtr; } - var item1Size = Marshal.SizeOf(); + } + private IntPtr _item5Ptr; - currentPtr = currentPtr->PNext; - T2 item2 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 4"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); - } - var item2Size = Marshal.SizeOf(); + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item5Ptr => (Chain*) _item5Ptr; - currentPtr = currentPtr->PNext; - T3 item3 = default; - if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 4"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 4"); + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef((Chain*) _item5Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item5Ptr)->PNext; + Marshal.StructureToPtr(value, _item5Ptr, true); + ((Chain*) _item5Ptr)->PNext = nextPtr; } - var item3Size = Marshal.SizeOf(); - - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; } + private IntPtr _item6Ptr; /// - /// Creates a new with 4 items. + /// Gets a pointer to the second item in the chain. /// - /// The chain to append to. - /// Item 3. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T3 item3 = default) - { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size; - var newSize = originalSize + item3Size; - - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - // Append the last structure - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - } + public Chain* Item6Ptr => (Chain*) _item6Ptr; /// - /// Creates a new with 5 items, by appending to - /// the end of this chain. + /// Gets or sets item #6 in the chain. /// - /// Item 4. - /// Type of Item 4 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T4 item4 = default) - where T4: struct, IExtendsChain + public T6 Item6 { - return new ManagedChain(this, item4); + get => Unsafe.AsRef((Chain*) _item6Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item6Ptr)->PNext; + Marshal.StructureToPtr(value, _item6Ptr, true); + ((Chain*) _item6Ptr)->PNext = nextPtr; + } } + private IntPtr _item7Ptr; - /// - public override IEnumerator GetEnumerator() + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item7Ptr => (Chain*) _item7Ptr; + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 { - yield return Head; - yield return Item1; - yield return Item2; - yield return Item3; + get => Unsafe.AsRef((Chain*) _item7Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item7Ptr)->PNext; + Marshal.StructureToPtr(value, _item7Ptr, true); + ((Chain*) _item7Ptr)->PNext = nextPtr; + } } + private IntPtr _item8Ptr; - /// - public override int Count => 4; + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item8Ptr => (Chain*) _item8Ptr; - /// - public override IChainable this[int index] - => index switch + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef((Chain*) _item8Ptr); + set { - 0 => Head, 1 => Item1, - 2 => Item2, - 3 => Item3, - _ => throw new IndexOutOfRangeException() - }; + value.StructureType(); + var nextPtr = ((Chain*) _item8Ptr)->PNext; + Marshal.StructureToPtr(value, _item8Ptr, true); + ((Chain*) _item8Ptr)->PNext = nextPtr; + } + } + private IntPtr _item9Ptr; /// - /// Deconstructs this chain. + /// Gets a pointer to the second item in the chain. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3) - { - head = Head; - item1 = Item1; - item2 = Item2; - item3 = Item3; - } + public Chain* Item9Ptr => (Chain*) _item9Ptr; - /// - public override void Dispose() + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + get => Unsafe.AsRef((Chain*) _item9Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item9Ptr)->PNext; + Marshal.StructureToPtr(value, _item9Ptr, true); + ((Chain*) _item9Ptr)->PNext = nextPtr; + } + } + private IntPtr _item10Ptr; - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item10Ptr => (Chain*) _item10Ptr; - // Free memory block - Marshal.FreeHGlobal(headPtr); + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef((Chain*) _item10Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item10Ptr)->PNext; + Marshal.StructureToPtr(value, _item10Ptr, true); + ((Chain*) _item10Ptr)->PNext = nextPtr; + } } -} - -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain -{ - private IntPtr _headPtr; + private IntPtr _item11Ptr; /// - /// Gets a pointer to the current head. + /// Gets a pointer to the second item in the chain. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public Chain* Item11Ptr => (Chain*) _item11Ptr; /// - /// Gets or sets the head of the chain. + /// Gets or sets item #11 in the chain. /// - public TChain Head + public T11 Item11 { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((Chain*) _item11Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + var nextPtr = ((Chain*) _item11Ptr)->PNext; + Marshal.StructureToPtr(value, _item11Ptr, true); + ((Chain*) _item11Ptr)->PNext = nextPtr; } } - - private IntPtr _item1Ptr; + private IntPtr _item12Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item12Ptr => (Chain*) _item12Ptr; /// - /// Gets or sets item #1 in the chain. + /// Gets or sets item #12 in the chain. /// - public T1 Item1 + public T12 Item12 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef((Chain*) _item12Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var nextPtr = ((Chain*) _item12Ptr)->PNext; + Marshal.StructureToPtr(value, _item12Ptr, true); + ((Chain*) _item12Ptr)->PNext = nextPtr; } } - private IntPtr _item2Ptr; + private IntPtr _item13Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item13Ptr => (Chain*) _item13Ptr; /// - /// Gets or sets item #2 in the chain. + /// Gets or sets item #13 in the chain. /// - public T2 Item2 + public T13 Item13 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef((Chain*) _item13Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var nextPtr = ((Chain*) _item13Ptr)->PNext; + Marshal.StructureToPtr(value, _item13Ptr, true); + ((Chain*) _item13Ptr)->PNext = nextPtr; } } - private IntPtr _item3Ptr; + private IntPtr _item14Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item14Ptr => (Chain*) _item14Ptr; /// - /// Gets or sets item #3 in the chain. + /// Gets or sets item #14 in the chain. /// - public T3 Item3 + public T14 Item14 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef((Chain*) _item14Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var nextPtr = ((Chain*) _item14Ptr)->PNext; + Marshal.StructureToPtr(value, _item14Ptr, true); + ((Chain*) _item14Ptr)->PNext = nextPtr; } } - private IntPtr _item4Ptr; + private IntPtr _item15Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item15Ptr => (Chain*) _item15Ptr; /// - /// Gets or sets item #4 in the chain. + /// Gets or sets item #15 in the chain. /// - public T4 Item4 + public T15 Item15 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef((Chain*) _item15Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var nextPtr = ((Chain*) _item15Ptr)->PNext; + Marshal.StructureToPtr(value, _item15Ptr, true); + ((Chain*) _item15Ptr)->PNext = nextPtr; } } /// - /// Creates a new with 5 items. + /// Creates a new with 16 items. /// /// The head of the chain. /// Item 1. /// Item 2. /// Item 3. /// Item 4. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// Item 15. + public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -1136,8 +9991,19 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul var item2Size = Marshal.SizeOf(); var item3Size = Marshal.SizeOf(); var item4Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size); + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + var item14Size = Marshal.SizeOf(); + var item15Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size + item15Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); @@ -1160,10 +10026,65 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul item4.StructureType(); Marshal.StructureToPtr(item4, _item4Ptr, false); ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + item5.StructureType(); + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + item6.StructureType(); + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + item7.StructureType(); + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + item8.StructureType(); + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + item9.StructureType(); + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + item10.StructureType(); + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + item11.StructureType(); + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + item12.StructureType(); + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + item13.StructureType(); + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + item14.StructureType(); + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + + _item15Ptr = _item14Ptr + item14Size; + item15.StructureType(); + Marshal.StructureToPtr(item15, _item15Ptr, false); + ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; } /// - /// Creates a new with 5 items from an existing unmanaged chain. + /// Creates a new with 16 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. @@ -1179,7 +10100,7 @@ public ManagedChain(out string errors, TChain chain) currentPtr = currentPtr->PNext; T1 item1 = default; if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 5"); + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 16"); else { expectedStructureType = item1.StructureType(); if (currentPtr->SType != expectedStructureType) { @@ -1196,7 +10117,7 @@ public ManagedChain(out string errors, TChain chain) currentPtr = currentPtr->PNext; T2 item2 = default; if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 5"); + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 16"); else { expectedStructureType = item2.StructureType(); if (currentPtr->SType != expectedStructureType) { @@ -1213,7 +10134,7 @@ public ManagedChain(out string errors, TChain chain) currentPtr = currentPtr->PNext; T3 item3 = default; if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 5"); + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 16"); else { expectedStructureType = item3.StructureType(); if (currentPtr->SType != expectedStructureType) { @@ -1230,7 +10151,7 @@ public ManagedChain(out string errors, TChain chain) currentPtr = currentPtr->PNext; T4 item4 = default; if (currentPtr is null) - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 5"); + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 16"); else { expectedStructureType = item4.StructureType(); if (currentPtr->SType != expectedStructureType) { @@ -1241,16 +10162,203 @@ public ManagedChain(out string errors, TChain chain) .AppendLine(); } else item4 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 5"); } var item4Size = Marshal.SizeOf(); + currentPtr = currentPtr->PNext; + T5 item5 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 16"); + else { + expectedStructureType = item5.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item5 = Unsafe.AsRef(currentPtr); + } + var item5Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T6 item6 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 16"); + else { + expectedStructureType = item6.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item6 = Unsafe.AsRef(currentPtr); + } + var item6Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T7 item7 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 16"); + else { + expectedStructureType = item7.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item7 = Unsafe.AsRef(currentPtr); + } + var item7Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T8 item8 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 16"); + else { + expectedStructureType = item8.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item8 = Unsafe.AsRef(currentPtr); + } + var item8Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T9 item9 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 16"); + else { + expectedStructureType = item9.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item9 = Unsafe.AsRef(currentPtr); + } + var item9Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T10 item10 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 16"); + else { + expectedStructureType = item10.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item10 = Unsafe.AsRef(currentPtr); + } + var item10Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T11 item11 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 16"); + else { + expectedStructureType = item11.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item11 = Unsafe.AsRef(currentPtr); + } + var item11Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T12 item12 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 16"); + else { + expectedStructureType = item12.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item12 = Unsafe.AsRef(currentPtr); + } + var item12Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T13 item13 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 16"); + else { + expectedStructureType = item13.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 14; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item13 = Unsafe.AsRef(currentPtr); + } + var item13Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T14 item14 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 16"); + else { + expectedStructureType = item14.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 15; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item14 = Unsafe.AsRef(currentPtr); + } + var item14Size = Marshal.SizeOf(); + + currentPtr = currentPtr->PNext; + T15 item15 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 15, expected length 16"); + else { + expectedStructureType = item15.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 16; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item15 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 16"); + } + var item15Size = Marshal.SizeOf(); + // Create string of errors errors = errorBuilder.ToString().Trim(); - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size); + _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size + item15Size); Marshal.StructureToPtr(head, _headPtr, false); _item1Ptr = _headPtr + headSize; @@ -1268,17 +10376,61 @@ public ManagedChain(out string errors, TChain chain) _item4Ptr = _item3Ptr + item3Size; Marshal.StructureToPtr(item4, _item4Ptr, false); ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item5, _item5Ptr, false); + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item6, _item6Ptr, false); + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item7, _item7Ptr, false); + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item8, _item8Ptr, false); + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item9, _item9Ptr, false); + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item10, _item10Ptr, false); + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item11, _item11Ptr, false); + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item12, _item12Ptr, false); + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + Marshal.StructureToPtr(item13, _item13Ptr, false); + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + Marshal.StructureToPtr(item14, _item14Ptr, false); + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + + _item15Ptr = _item14Ptr + item14Size; + Marshal.StructureToPtr(item15, _item15Ptr, false); + ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; } /// - /// Creates a new with 5 items. + /// Creates a new with 16 items. /// /// The chain to append to. - /// Item 4. + /// Item 15. /// /// Do not forget to dispose the chain if you are no longer using it. /// - public ManagedChain(ManagedChain previous, T4 item4 = default) + public ManagedChain(ManagedChain previous, T15 item15 = default) { // Calculate memory requirements var headSize = Marshal.SizeOf(); @@ -1286,9 +10438,20 @@ public ManagedChain(ManagedChain previous, T4 item4 = defaul var item2Size = Marshal.SizeOf(); var item3Size = Marshal.SizeOf(); var item4Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size; - var newSize = originalSize + item4Size; + var item5Size = Marshal.SizeOf(); + var item6Size = Marshal.SizeOf(); + var item7Size = Marshal.SizeOf(); + var item8Size = Marshal.SizeOf(); + var item9Size = Marshal.SizeOf(); + var item10Size = Marshal.SizeOf(); + var item11Size = Marshal.SizeOf(); + var item12Size = Marshal.SizeOf(); + var item13Size = Marshal.SizeOf(); + var item14Size = Marshal.SizeOf(); + var item15Size = Marshal.SizeOf(); + + var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size; + var newSize = originalSize + item15Size; _headPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed @@ -1304,10 +10467,43 @@ public ManagedChain(ManagedChain previous, T4 item4 = defaul ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; _item4Ptr = _item3Ptr + item3Size; - // Append the last structure - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + + _item5Ptr = _item4Ptr + item4Size; + ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + + _item6Ptr = _item5Ptr + item5Size; + ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + + _item7Ptr = _item6Ptr + item6Size; + ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + + _item8Ptr = _item7Ptr + item7Size; + ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + + _item9Ptr = _item8Ptr + item8Size; + ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + + _item10Ptr = _item9Ptr + item9Size; + ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + + _item11Ptr = _item10Ptr + item10Size; + ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + + _item12Ptr = _item11Ptr + item11Size; + ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + + _item13Ptr = _item12Ptr + item12Size; + ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + + _item14Ptr = _item13Ptr + item13Size; + ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + + _item15Ptr = _item14Ptr + item14Size; + // Append the last structure + item15.StructureType(); + Marshal.StructureToPtr(item15, _item15Ptr, false); + ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; } /// @@ -1318,10 +10514,21 @@ public override IEnumerator GetEnumerator() yield return Item2; yield return Item3; yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + yield return Item8; + yield return Item9; + yield return Item10; + yield return Item11; + yield return Item12; + yield return Item13; + yield return Item14; + yield return Item15; } /// - public override int Count => 5; + public override int Count => 16; /// public override IChainable this[int index] @@ -1331,6 +10538,17 @@ public override IChainable this[int index] 2 => Item2, 3 => Item3, 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + 8 => Item8, + 9 => Item9, + 10 => Item10, + 11 => Item11, + 12 => Item12, + 13 => Item13, + 14 => Item14, + 15 => Item15, _ => throw new IndexOutOfRangeException() }; @@ -1342,13 +10560,35 @@ public override IChainable this[int index] /// Item 2. /// Item 3. /// Item 4. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4) + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// Item 15. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10, out T11 item11, out T12 item12, out T13 item13, out T14 item14, out T15 item15) { head = Head; item1 = Item1; item2 = Item2; item3 = Item3; item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + item8 = Item8; + item9 = Item9; + item10 = Item10; + item11 = Item11; + item12 = Item12; + item13 = Item13; + item14 = Item14; + item15 = Item15; } /// @@ -1367,6 +10607,28 @@ public override void Dispose() Marshal.DestroyStructure(item3Ptr); var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); Marshal.DestroyStructure(item4Ptr); + var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item5Ptr); + var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item6Ptr); + var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item7Ptr); + var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item8Ptr); + var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item9Ptr); + var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item10Ptr); + var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item11Ptr); + var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item12Ptr); + var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item13Ptr); + var item14Ptr = Interlocked.Exchange(ref _item14Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item14Ptr); + var item15Ptr = Interlocked.Exchange(ref _item15Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item15Ptr); // Free memory block Marshal.FreeHGlobal(headPtr); diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt index 3747a699c9..c6355fa39e 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt @@ -2,7 +2,7 @@ <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <# - var maximumItems = 5; // TODO use 16/32 in production + var maximumItems = 16; string parameterDocs(int index, string prefix) { diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj index 5a7f851a90..643b5beaf5 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0 10 enable enable From 1c8dbda2ac88e3e0b16e3e4dc86cfd21a54fb3ad Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sun, 7 Nov 2021 13:07:54 +0000 Subject: [PATCH 24/34] docs: Initial work on Managed Chaining Proposal. --- ...Struct Chaining - #2 Unmanaged Chaining.md | 4 + ...n Struct Chaining - #3 Managed Chaining.md | 280 +++++++++++++++++- 2 files changed, 282 insertions(+), 2 deletions(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md index baf8f809b6..b627be5c9a 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md @@ -1,5 +1,9 @@ # Summary +**_This proposal is dependent +on [Proposal - Vulkan Struct Chaining - #1 StructureType correction](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md) +._** + This proposal presents a lightweight mechanism for fluently building Vulkan Structure Chains. You may wish to start with the [Usage section below](#Usage) to aid understanding. There is also a fully working prototype [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/). diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md index 6039b01fcd..7b8d3e8f6c 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md @@ -1,17 +1,293 @@ # Summary -TODO + +**_This proposal is dependent +on [Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) +._** + +This proposal presents a _managed_ mechanism for safely building, and storing, Vulkan Structure Chains. You may wish to +start with the [previous proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md), +followed by the [Usage section below](#Usage) to aid understanding. There is also a fully working prototype +[in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/). + +The [previous proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) provided a +lightweight mechanism for building structure chains, but the responsibility for ensuring that the provided structures +did not move remained with the consumer. This provided a useful mechanism for reducing bugs (through compile time and +run time validation of `SType` and `PNext`) and making more readable and compact code, whilst not sacrificing +performance. + +However, many consumers are uncomfortable with pointers, and are especially prone to introducing bugs when placing +structs onto the heap. This proposal provides a convenient `ManagedChain` class, and multiple +descendent `ManagedChain` classes to safely fix the structures in memory and prevent pointer bugs. + +Whenever a structure is loaded into the `ManagedChain` it's `SType` and `PNext` are forced to be correct, preventing +errors. Structures can be replaced at any time, and we be inserted efficiently into the chain as an O(1) operation. # Contributors + - [Craig Dean, DevDecoder](https://github.com/thargy) # Current Status + - [x] Proposed - [ ] Discussed with API Review Board (ARB) - [ ] Approved - [ ] Implemented # Design Decisions -TODO + +- There are no requirements to extend `BuildTools`, or add any additional information to the `IChainable` structures. +- Although the `ManagedChain` generic classes are auto-generated (for convenience) this is done using T4 + templating, an implementation of which is + provided [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt). + +Open questions: + +- Should we expose 8, 16 or 32 `ManagedChain` classes? +- Do we want to stick with `TChain chain, T1 item1`, or use `T1 item1, T2 item2` ala `Tuple`? +- Although the constructors used by `ManagedChain.Create` and `ManagedChain.Load` could be made `internal`, I don't + propose we do so. Primarily, the main benefit of the static methods is type inference, but, as chain building is + frequently done with defaults then direct constructor access does not have a disadvantage, and can take advantage of + implicit typing when assigning to an already typed field/property. Having both forms available is therefore + convenient. +- Currently `ManagedChain` is the smallest chain, there is a strong case to be made for + a `ManagedChain`. +- The current `Load` methods expect an unmanaged chain that matches the supplied type constraints, and is of the same + length. This is useful, as coders will normally expect a particular chain. We could additionally add more lax `Import` + methods that will import an unmanaged chain into a managed chain by populating any positions with structure types + found in the unmanaged chain, no matter at what position they are found. This is not entirely unreasonable as the + order of chains (after the start) is not fixed in Vulkan, and it will allow importing existing chains where the order + doesn't matter. +- Similar to `Append` do we want a `Truncate` method to trim the end of a chain? +- Similar to `Append` and `Truncate` we could also add `Insert` and `Remove` methods, however this is more complex, as + we'd have to generate multiples of each, for example: + +```csharp +pubilc class ManagedCache ... { + // There would of these methods (not too bad to be fair, the worst case would be maxsize -1 as we + // wouldn't add these methods to the largest possible ManagedCache) + public ManagedCache InsertBeforeHead(TChain newHead) {...} + public ManagedCache InsertBeforeItem1(TNew newValue) {...} + public ManagedCache InsertBeforeItem2(TNew newValue) {...} + + // There would be size-2 of these methods (so wouldn't exist on `ManagedCache`) + public ManagedCache RemoveItem1(out T1 removedValue) {...} + + // This is pretty trivial to add (also wouldn't exist on `ManagedCache`) + public ManagedCache Truncate(out T2 removedValue) {...} +} +``` + +# Usage + +### Creation + +For example: + +```csharp +using var chain = new ManagedChain(); + +// Ensure all STypes set correctly +Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); +Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain.Item2.SType); + +// Ensure pointers set correctly +Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); +Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); +Assert.Equal((nint) 0, (nint) chain.Item2.PNext); +``` + +The structures are held in unmanaged memory, preventing movement by the GC, and ensuring that the ptrs remain fixed. + +You can also use the `ManagedChain.Create(...)` static methods to create `ManagedChain`s. + +### Modifying values + +We can easily modify any value in the `ManagedChain`, and it will maintain the ptrs automatically, e.g.: + +```csharp +using var chain = new ManagedChain(item1: new PhysicalDeviceDescriptorIndexingFeatures +{ + // We can set any non-default values, note we do not need to set SType or PNext + // indeed they will be overwritten. + ShaderInputAttachmentArrayDynamicIndexing = true +}); + +// Ensure all STypes set correctly +Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); +Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain.Item2.SType); + +// Ensure pointers set correctly +Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); +Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); +Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + +// Check our value was set +Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + +var item1Ptr = chain.Item1Ptr; + +// Overwrite Item1 +chain.Item1 = new PhysicalDeviceDescriptorIndexingFeatures +{ + // Again we do not need to set SType or PNext, which will be set to the correct values + ShaderInputAttachmentArrayDynamicIndexing = false +}; + +// Check our value was cleared +Assert.False(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + +// Note all the pointers are still correct (and have not changed) +Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); +Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); +Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + +// As is the SType +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); +``` + +**Note** When we update any item in the chain it overwrites the existing memory, so the ptrs remain fixed. It also +ensures the PNext value is maintained. + +### Appending to a chain + +You can call `Append` on a `ManagedChain` to efficiently create a new, larger, `ManagedChain` with a new item appended +to the end, e.g: + +```csharp +using var chain = new ManagedChain( + item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true}); + +// The new chain, will efficiently copy the old chain and append a new structure to the end +using var newChain = chain.Append(); +// You will usualy wish to dispose the old chain here, the two chains are now independent of each other. + +// Check the flag from the first chain is still set in the new chain. +Assert.True(newChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); +``` + +### Loading from an unmanaged chain + +If you have created an unmanaged chain and would like to load that into a `ManagedChain` you can use one of the +`ManagedChain.Load` methods: + +```csharp +// Load an unmanaged chain +var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures +{ + ShaderInputAttachmentArrayDynamicIndexing = true +}; +PhysicalDeviceFeatures2 +.Chain(out var unmanagedChain) +.SetNext(ref indexingFeatures) +.AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + +// Loads a new managed chain from an unmanaged chain +using var managedChain = + ManagedChain.Load(unmanagedChain, out var errors); + +// Check we had no loading errors +Assert.Equal("", errors); + +// Check the flag still set +Assert.True(managedChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); +``` + +The full version of the `Load` method returns an output parameter `errors` as it's first parameter. The `errors` +parameter will be `string.Empty` if there are no errors, otherwise each line will contain a separate error for each +issue found during loading. There is also an overload that accepts a single argument `chain` for when you don't care if +there are any errors. Either method always succeeds, even if the unmanaged chain doesn't match exactly - for example it +is shorter or longer than the chain being loaded, or if the managed chain has different structure types in any of the +positions. Any structure type in the expected position will always be loaded into the new `ManagedChain`. + +```csharp +var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures +{ + ShaderInputAttachmentArrayDynamicIndexing = true +}; +// Load an unmanaged chain +DeviceCreateInfo + .Chain(out var unmanagedChain) + .AddNext(out PhysicalDeviceFeatures2 features2) + .SetNext(ref indexingFeatures) + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + +// Loads a new managed chain from an unmanaged chain +using var managedChain = + new ManagedChain< + DeviceCreateInfo, + // Note we are supplied a PhysicalDeviceFeatures2 here from the unmanaged chain + PhysicalDeviceAccelerationStructureFeaturesKHR, + PhysicalDeviceDescriptorIndexingFeatures, + PhysicalDeviceAccelerationStructureFeaturesKHR, + // Note that the unmanaged chain did not supply a 5th entry + PhysicalDeviceFeatures2>(unmanagedChain, out var errors); + +// Check for errors +Assert.Equal( +@"The unmanaged chain has a structure type PhysicalDeviceFeatures2Khr at position 2; expected PhysicalDeviceAccelerationStructureFeaturesKhr +The unmanaged chain was length 4, expected length 5", + errors); + +// Despite the errors indexing features was at the right location so was loaded +Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); +``` + +Notice that the above form use the constructor as an alternative. + +### IReadOnlyList + +All the fully generic `ManageChain` types extend `ManagedChain` which implements `IDisposable` +and `IReadOnlyList`. The latter allowing for easy consumption of any `ManagedChain`, e.g.: + +```csharp +using var chain = new ManagedChain(); + +Assert.Equal(3, chain.Count); + +// Ensure all STypes set correctly using indexer +Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain[0].StructureType()); +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain[1].StructureType()); +Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain[2].StructureType()); + +Assert.Throws(() => chain[3]); + +// Get array using IEnumerable implementation +IChainable[] structures = chain.ToArray(); + +// Check concrete types +Assert.IsType(structures[0]); +Assert.IsType(structures[1]); +Assert.IsType(structures[2]); +``` + +### Deconstruction + +Each `ManageChain` has a corresponding deconstructor for convenience, e.g.: + +```csharp +using var chain = new ManagedChain(); + +var (physicalDeviceFeatures2, indexingFeatures, accelerationStructureFeaturesKhr) = chain; + +// Ensure all STypes set correctly +Assert.Equal(StructureType.PhysicalDeviceFeatures2, physicalDeviceFeatures2.SType); +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); +Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeaturesKhr.SType); +``` + +### Disposal + +As each `ManagedChain` holds the underlying structures in unmanaged memory (to prevent them being moved and their +pointers being invalidated), then it is critical you dispose them; either by calling `Dispose()` or by using a `using` +statement. # Proposed API + TODO \ No newline at end of file From af6c5a8905f1509dd7ada4ab08917fb19b939d36 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sun, 7 Nov 2021 15:31:49 +0000 Subject: [PATCH 25/34] docs: Finished draft proposal for Managed Chains --- ...n Struct Chaining - #3 Managed Chaining.md | 352 +++++++++++++++--- 1 file changed, 308 insertions(+), 44 deletions(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md index 7b8d3e8f6c..8ffb1cb6e5 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md @@ -7,7 +7,7 @@ on [Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining](Proposal%20-%20Vu This proposal presents a _managed_ mechanism for safely building, and storing, Vulkan Structure Chains. You may wish to start with the [previous proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md), followed by the [Usage section below](#Usage) to aid understanding. There is also a fully working prototype -[in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/). +[in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining). The [previous proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) provided a lightweight mechanism for building structure chains, but the responsibility for ensuring that the provided structures @@ -19,8 +19,8 @@ However, many consumers are uncomfortable with pointers, and are especially pron structs onto the heap. This proposal provides a convenient `ManagedChain` class, and multiple descendent `ManagedChain` classes to safely fix the structures in memory and prevent pointer bugs. -Whenever a structure is loaded into the `ManagedChain` it's `SType` and `PNext` are forced to be correct, preventing -errors. Structures can be replaced at any time, and we be inserted efficiently into the chain as an O(1) operation. +Whenever a structure is loaded into the `ManagedChain` its `SType` and `PNext` are forced to be correct, preventing +errors. Structures can be replaced at any time, and will be inserted efficiently into the chain as an O(1) operation. # Contributors @@ -39,6 +39,12 @@ errors. Structures can be replaced at any time, and we be inserted efficiently i - Although the `ManagedChain` generic classes are auto-generated (for convenience) this is done using T4 templating, an implementation of which is provided [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt). +- For improved performance, the chain's structures are held in a single block of contiguous unmanaged memory, as the + memory is unmanaged, the position of the structures remains fixed, even though the containing object can be safely + moved around by the GC in the heap. +- The structure accessors return a copy of the structures, and always correct the `SType` and `PNext` on input. Even + though the `PNext` values are exposed there is no way to modify them from outside the class, guaranteeing their + safety. Open questions: @@ -58,12 +64,14 @@ Open questions: order of chains (after the start) is not fixed in Vulkan, and it will allow importing existing chains where the order doesn't matter. - Similar to `Append` do we want a `Truncate` method to trim the end of a chain? -- Similar to `Append` and `Truncate` we could also add `Insert` and `Remove` methods, however this is more complex, as - we'd have to generate multiples of each, for example: +- Similar to `Append` and `Truncate` we could also add `Insert` and `Remove` methods, though slightly more complex, as + we'd have to generate multiples of each, it is not difficult to do, for example: ```csharp pubilc class ManagedCache ... { - // There would of these methods (not too bad to be fair, the worst case would be maxsize -1 as we + ... + + // There would be of these methods (not too bad to be fair, the worst case would be maxsize -1 as we // wouldn't add these methods to the largest possible ManagedCache) public ManagedCache InsertBeforeHead(TChain newHead) {...} public ManagedCache InsertBeforeItem1(TNew newValue) {...} @@ -81,7 +89,9 @@ pubilc class ManagedCache ... { ### Creation -For example: +The following will create a chain starting with `PhysicalDeviceFeatures2`, pointing +to `PhysicalDeviceDescriptorIndexingFeatures` and finishing with a `PhysicalDeviceAccelerationStructureFeaturesKHR` +structure: ```csharp using var chain = new ManagedChain(); +``` -You can also use the `ManagedChain.Create(...)` static methods to create `ManagedChain`s. +or, using generic type inference: + +```csharp +using var chain = ManagedChain.Create( + new DeviceCreateInfo { Flags = 1U }, + default(PhysicalDeviceFeatures2), + default(PhysicalDeviceDescriptorIndexingFeatures) +); +``` ### Modifying values -We can easily modify any value in the `ManagedChain`, and it will maintain the ptrs automatically, e.g.: +We can easily modify any value in the `ManagedChain`, and it will maintain the pointers automatically, e.g.: ```csharp -using var chain = new ManagedChain(item1: new PhysicalDeviceDescriptorIndexingFeatures -{ - // We can set any non-default values, note we do not need to set SType or PNext - // indeed they will be overwritten. - ShaderInputAttachmentArrayDynamicIndexing = true -}); +using var chain = ManagedChain.Create< + DeviceCreateInfo, + PhysicalDeviceFeatures2, + PhysicalDeviceDescriptorIndexingFeatures>(); // Ensure all STypes set correctly -Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); -Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); -Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain.Item2.SType); +Assert.Equal(StructureType.DeviceCreateInfo, chain.Head.SType); +Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Item1.SType); +Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item2.SType); // Ensure pointers set correctly Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); Assert.Equal((nint) 0, (nint) chain.Item2.PNext); -// Check our value was set -Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); +Assert.Equal(0U, chain.Head.Flags); -var item1Ptr = chain.Item1Ptr; +var headPtr = chain.HeadPtr; -// Overwrite Item1 -chain.Item1 = new PhysicalDeviceDescriptorIndexingFeatures -{ - // Again we do not need to set SType or PNext, which will be set to the correct values - ShaderInputAttachmentArrayDynamicIndexing = false -}; +// Get the current head (this is a copy) +var head = chain.Head; +// Update the flags +head.Flags = 1U; +// Update the chain +chain.Head = head; -// Check our value was cleared -Assert.False(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); +Assert.Equal(1U, chain.Head.Flags); -// Note all the pointers are still correct (and have not changed) +// The head ptr should not change, as we overwrite the same memory location with the new value +Assert.Equal((nint) headPtr, (nint) chain.HeadPtr); +// But the next pointer should not change Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); -Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); -Assert.Equal((nint) 0, (nint) chain.Item2.PNext); - -// As is the SType -Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); ``` -**Note** When we update any item in the chain it overwrites the existing memory, so the ptrs remain fixed. It also -ensures the PNext value is maintained. +**Note** When we update any item in the chain it overwrites the existing memory, so the pointers remain fixed. It also +ensures the `PNext` value pointing to it is maintained. ### Appending to a chain @@ -169,6 +188,10 @@ using var newChain = chain.Append(unmanagedChain, out var errors); + PhysicalDeviceAccelerationStructureFeaturesKHR>(out var errors, unmanagedChain); // Check we had no loading errors -Assert.Equal("", errors); +Assert.Equal(string.Empty, errors); // Check the flag still set Assert.True(managedChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); @@ -225,7 +248,7 @@ using var managedChain = PhysicalDeviceDescriptorIndexingFeatures, PhysicalDeviceAccelerationStructureFeaturesKHR, // Note that the unmanaged chain did not supply a 5th entry - PhysicalDeviceFeatures2>(unmanagedChain, out var errors); + PhysicalDeviceFeatures2>(out var errors, unmanagedChain ); // Check for errors Assert.Equal( @@ -237,7 +260,8 @@ The unmanaged chain was length 4, expected length 5", Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); ``` -Notice that the above form use the constructor as an alternative. +Notice that the above form uses the equivalent constructor as an alternative to the `Load` method. There is no +equivalent constructor to `Load(TChain)` as that would be ambiguous. ### IReadOnlyList @@ -290,4 +314,244 @@ statement. # Proposed API -TODO \ No newline at end of file +## Abstract base class + +The `ManagedChain`, non-generic abstract base class provides an abstract implementation of `IReadOnlyList`, +and defines static `Create` and `Load` methods for each size of chain. + +```csharp +public abstract class ManagedChain : IReadOnlyList, IDisposable +{ + /// + public abstract IEnumerator GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + public abstract int Count { get; } + + /// + public abstract IChainable this[int index] { get; } + + /// + public abstract void Dispose(); + + /// + /// Creates a new with 2 items. + /// + /// The head of the chain. + /// Item 1. + /// The chain type + /// Type of Item 1. + /// A new with 2 items. + public static ManagedChain Create(TChain head = default, T1 item1 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + { + return new(head, item1); + } + + /// + /// Loads a new with 2 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 2 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + { + return new(out errors, chain); + } + + // Only showing one example of Create/Load methods + ... +} +``` + +## Concrete generic classes + +A class is generated for each valid size of a chain, here is one example: + +```csharp +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain +{ + private IntPtr _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _headPtr)->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ((Chain*) _headPtr)->PNext = nextPtr; + } + } + + private IntPtr _item1Ptr; + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) _item1Ptr; + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef((Chain*) _item1Ptr); + set + { + value.StructureType(); + var nextPtr = ((Chain*) _item1Ptr)->PNext; + Marshal.StructureToPtr(value, _item1Ptr, true); + ((Chain*) _item1Ptr)->PNext = nextPtr; + } + } + + /// + /// Creates a new with 2 items. + /// + /// The head of the chain. + /// Item 1. + public ManagedChain(TChain head = default, T1 item1 = default) + { + // Calculate memory requirements + var headSize = Marshal.SizeOf(); + var item1Size = Marshal.SizeOf(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + item1.StructureType(); + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + } + + /// + /// Creates a new with 2 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + { + // Load existing chain first, so any errors occur before we allocate memory + var head = chain; + var headSize = Marshal.SizeOf(); + var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); + StructureType expectedStructureType; + StringBuilder errorBuilder = new StringBuilder(); + + currentPtr = currentPtr->PNext; + T1 item1 = default; + if (currentPtr is null) + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); + else { + expectedStructureType = item1.StructureType(); + if (currentPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(currentPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else + item1 = Unsafe.AsRef(currentPtr); + if (currentPtr->PNext is not null) + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); + } + var item1Size = Marshal.SizeOf(); + + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + + _headPtr = Marshal.AllocHGlobal(headSize + item1Size); + Marshal.StructureToPtr(head, _headPtr, false); + + _item1Ptr = _headPtr + headSize; + Marshal.StructureToPtr(item1, _item1Ptr, false); + ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + } + + /// + /// Creates a new with 3 items, by appending to + /// the end of this chain. + /// + /// Item 2. + /// Type of Item 2 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T2 item2 = default) + where T2: struct, IExtendsChain + { + return new ManagedChain(this, item2); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + } + + /// + public override int Count => 2; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, 1 => Item1, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + public void Deconstruct(out TChain head, out T1 item1) + { + head = Head; + item1 = Item1; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); + if (headPtr == IntPtr.Zero) return; + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); + Marshal.DestroyStructure(item1Ptr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} +``` \ No newline at end of file From 75f03712e45e141f37933902d1bc50f1f04e37c0 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sun, 7 Nov 2021 21:33:06 +0000 Subject: [PATCH 26/34] feat: Numerous enhancements to ManagedChains * IChainable now exposes `Chain* PNext` property. * Added `ManagedChain` as smallest chain (just the head) * All `IntPtr`s are replaced with `nint`s. * Pointer offsets are calculated once per chain type and stored in statics, meaning that a chain contains a single `nint` field internally, making it incredibly lightweight. Getting the sizes once may also improve the performance, and has simplified the code. * Various fixes to ensure tail always has `PNext` set to `null` (0). * Added `Truncate` instance methods. --- .../TestChains.cs | 16 +- .../TestCompilation.cs | 45 +- .../TestManagedChains.cs | 123 +- .../PrototypeStructChaining/Chain.cs | 8 + .../ChainExtensions.cs | 30 +- .../DeviceCreateInfo.cs | 29 +- .../PrototypeStructChaining/IChainStart.cs | 2 +- .../PrototypeStructChaining/IChainable.cs | 1 + .../IStructuredType.cs | 2 +- .../ManagedChain.gen.cs | 10242 +++++++++------- .../ManagedChain.gen.tt | 366 +- ...lDeviceAccelerationStructureFeaturesKHR.cs | 7 + ...hysicalDeviceDescriptorIndexingFeatures.cs | 7 + .../PhysicalDeviceFeatures2.cs | 7 + 14 files changed, 6539 insertions(+), 4346 deletions(-) diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs index 5d5080c6ff..0debaa5543 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs @@ -24,8 +24,11 @@ public unsafe void TestAddNext() // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); - Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, - accelerationStructureFeaturesKhr.SType); + Assert.Equal + ( + StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, + accelerationStructureFeaturesKhr.SType + ); // Check indices Assert.Equal(1, features2.IndexOf(ref indexingFeatures)); @@ -77,8 +80,11 @@ public unsafe void TestSetNext() Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); - Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, - accelerationStructureFeaturesKhr.SType); + Assert.Equal + ( + StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, + accelerationStructureFeaturesKhr.SType + ); Assert.True(indexingFeatures.ShaderInputAttachmentArrayDynamicIndexing); Assert.True(accelerationStructureFeaturesKhr.AccelerationStructure); @@ -174,4 +180,4 @@ public unsafe void TestWithoutChain() Assert.Equal(1U, createInfo.Flags); } -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs index 21ab41240c..0d4c192599 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs @@ -13,12 +13,14 @@ namespace PrototypeStructChaining.Test; public class TestCompilation { - private static readonly Lazy> References = new(() => - ((string?) AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") ?? string.Empty) - .Split(Path.PathSeparator) - .Select(r => MetadataReference.CreateFromFile(r)) - .Concat(new[] {MetadataReference.CreateFromFile(typeof(StructureType).Assembly.Location)}) - .ToArray() + private static readonly Lazy> References = new + ( + () => + ((string?) AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") ?? string.Empty) + .Split(Path.PathSeparator) + .Select(r => MetadataReference.CreateFromFile(r)) + .Concat(new[] {MetadataReference.CreateFromFile(typeof(StructureType).Assembly.Location)}) + .ToArray() ); private static readonly string CodeTemplate = @" @@ -36,31 +38,40 @@ public void DoTest() private IReadOnlyList CheckCompile(string code) { var assemblyName = Path.GetRandomFileName(); - var compilation = CSharpCompilation.Create( + var compilation = CSharpCompilation.Create + ( assemblyName, new[] {CSharpSyntaxTree.ParseText(string.Format(CodeTemplate, code))}, References.Value, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); using var ms = new MemoryStream(); var result = compilation.Emit(ms); if (result.Success) + { return Array.Empty(); + } - return result.Diagnostics.Where(diagnostic => - diagnostic.IsWarningAsError || - diagnostic.Severity == DiagnosticSeverity.Error) + return result.Diagnostics.Where + ( + diagnostic => + diagnostic.IsWarningAsError || + diagnostic.Severity == DiagnosticSeverity.Error + ) .ToArray(); } [Fact] public unsafe void TestCantAddUnsupportedNext() { - var diagnostics = CheckCompile( + var diagnostics = CheckCompile + ( @"PhysicalDeviceFeatures2 .Chain(out var features2) - .AddNext(out DeviceCreateInfo createInfo);"); + .AddNext(out DeviceCreateInfo createInfo);" + ); Assert.Single(diagnostics); var error = diagnostics.First(); @@ -71,11 +82,13 @@ public unsafe void TestCantAddUnsupportedNext() [Fact] public unsafe void TestCanAddSupportedNext() { - var diagnostics = CheckCompile( + var diagnostics = CheckCompile + ( @"DeviceCreateInfo .Chain(out var createInfo) - .AddNext(out PhysicalDeviceFeatures2 features2);"); + .AddNext(out PhysicalDeviceFeatures2 features2);" + ); Assert.Empty(diagnostics); } -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs index 9e36831cbd..6f212a3d1b 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs @@ -63,12 +63,15 @@ public unsafe void TestManagedChainReplaceHead() public unsafe void TestManagedChainReplaceMiddle() { using var chain = new ManagedChain(item1: new PhysicalDeviceDescriptorIndexingFeatures - { - // We can set any non-default values, note we do not need to set SType or PNext - // indeed they will be overwritten. - ShaderInputAttachmentArrayDynamicIndexing = true - }); + PhysicalDeviceAccelerationStructureFeaturesKHR> + ( + item1: new PhysicalDeviceDescriptorIndexingFeatures + { + // We can set any non-default values, note we do not need to set SType or PNext + // indeed they will be overwritten. + ShaderInputAttachmentArrayDynamicIndexing = true + } + ); // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); @@ -104,11 +107,50 @@ public unsafe void TestManagedChainReplaceMiddle() Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); } + [Fact] + public unsafe void TestManagedChainDuplicate() + { + using var chain = new ManagedChain + ( + item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true} + ); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) 0, (nint) chain.Item1.PNext); + + // Check flag set + Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + using var newChain = chain.Duplicate(); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) 0, (nint) chain.Item1.PNext); + + // Check flag set + Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + // Check we have new copies + Assert.NotEqual((nint) chain.HeadPtr, (nint) newChain.HeadPtr); + Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); + } + [Fact] public unsafe void TestManagedChainAppend() { - using var chain = new ManagedChain( - item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true}); + using var chain = new ManagedChain + ( + item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true} + ); // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); @@ -141,6 +183,52 @@ public unsafe void TestManagedChainAppend() Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); } + [Fact] + public unsafe void TestManagedChainTruncate() + { + using var chain = + ManagedChain.Create< + PhysicalDeviceFeatures2, + PhysicalDeviceDescriptorIndexingFeatures, + PhysicalDeviceAccelerationStructureFeaturesKHR> + ( + item2: new PhysicalDeviceAccelerationStructureFeaturesKHR + {AccelerationStructure = true} + ); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, chain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); + Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + + // Check flag set + Assert.True(chain.Item2.AccelerationStructure); + + using var newChain = chain.Truncate(out var accelerationStructure); + + Assert.Equal(2, newChain.Count); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, newChain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, newChain.Item1.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) newChain.Item1Ptr, (nint) newChain.Head.PNext); + Assert.Equal((nint) 0, (nint) newChain.Item1.PNext); + + // Check removed type flag + Assert.True(accelerationStructure.AccelerationStructure); + + // Check we have new copies + Assert.NotEqual((nint) chain.HeadPtr, (nint) newChain.HeadPtr); + Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); + } + [Fact] public unsafe void TestManagedChainLoad() { @@ -202,9 +290,11 @@ public unsafe void TestManagedChainLoadWithError() PhysicalDeviceFeatures2>(out var errors, unmanagedChain); // Check for errors - Assert.Equal( + Assert.Equal + ( @"The unmanaged chain has a structure type PhysicalDeviceFeatures2Khr at position 2; expected PhysicalDeviceAccelerationStructureFeaturesKhr -The unmanaged chain was length 4, expected length 5", errors); +The unmanaged chain was length 4, expected length 5", errors + ); // Despite the errors indexing features was at the right location so was loaded Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); @@ -245,7 +335,7 @@ public unsafe void TestReadOnlyList() PhysicalDeviceAccelerationStructureFeaturesKHR>(); Assert.Equal(3, chain.Count); - + // Ensure all STypes set correctly using indexer Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain[0].StructureType()); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain[1].StructureType()); @@ -254,8 +344,8 @@ public unsafe void TestReadOnlyList() Assert.Throws(() => chain[3]); // Get array using IEnumerable implementation - IChainable[] structures = chain.ToArray(); - + var structures = chain.ToArray(); + // Check concrete types Assert.IsType(structures[0]); Assert.IsType(structures[1]); @@ -269,10 +359,11 @@ public unsafe void TestDeconstructor() PhysicalDeviceAccelerationStructureFeaturesKHR>(); var (physicalDeviceFeatures2, indexingFeatures, accelerationStructureFeaturesKhr) = chain; - + // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, physicalDeviceFeatures2.SType); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); - Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeaturesKhr.SType); + Assert.Equal + (StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeaturesKhr.SType); } -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs index 78984e2678..4764a845bb 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs @@ -15,6 +15,7 @@ public struct Chain : IChainable /// The structure type. /// public StructureType SType; + /// /// The next struct in the chain, if any; otherwise . /// @@ -26,4 +27,11 @@ StructureType IStructuredType.StructureType() { return SType; } + + /// + unsafe Chain* IChainable.PNext + { + get => (Chain*) PNext; + set => PNext = value; + } } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs index 4c0bf8ebde..51c36f6393 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs @@ -33,8 +33,12 @@ public static class ChainExtensions /// .SetNext(ref accelerationStructureFeaturesKhr); /// /// - public static unsafe ref TChain SetNext(this ref TChain chain, ref TNext value, - bool alwaysAdd = false) + public static unsafe ref TChain SetNext + ( + this ref TChain chain, + ref TNext value, + bool alwaysAdd = false + ) where TChain : struct, IChainStart where TNext : struct, IExtendsChain { @@ -52,7 +56,11 @@ public static unsafe ref TChain SetNext(this ref TChain chain, re if (!alwaysAdd && currentPtr->SType == structureType) { // We have an existing structure, replace it. - if (previousPtr is not null) previousPtr->PNext = valuePtr; + if (previousPtr is not null) + { + previousPtr->PNext = valuePtr; + } + valuePtr->PNext = nextPtr; return ref chain; @@ -98,7 +106,10 @@ public static unsafe ref TChain AddNext(this ref TChain chain, ou // Find end of chain var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - while (currentPtr->PNext is not null) currentPtr = currentPtr->PNext; + while (currentPtr->PNext is not null) + { + currentPtr = currentPtr->PNext; + } // Create new entry and set it's structure type next = default; @@ -147,7 +158,11 @@ public static unsafe ref TChain TryAddNext(this ref TChain chain, } var nextPtr = currentPtr->PNext; - if (nextPtr is null) break; + if (nextPtr is null) + { + break; + } + currentPtr = nextPtr; } while (true); @@ -178,11 +193,14 @@ public static unsafe int IndexOf(this ref TChain chain, ref TNext do { if (currentPtr == valuePtr) + { return index; + } + currentPtr = currentPtr->PNext; index++; } while (currentPtr is not null); return -1; } -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs index d6f477d8cb..292c2bb96f 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs @@ -14,18 +14,28 @@ public struct DeviceCreateInfo : IChainStart // NOTE Truncated for example - public unsafe DeviceCreateInfo( + public unsafe DeviceCreateInfo + ( StructureType? sType = StructureType.DeviceCreateInfo, void* pNext = null, - uint? flags = null) + uint? flags = null + ) : this() { if (sType.HasValue) + { SType = sType.Value; + } + if ((IntPtr) pNext != IntPtr.Zero) + { PNext = pNext; + } + if (flags.HasValue) + { Flags = flags.Value; + } // NOTE Truncated for example } @@ -36,8 +46,10 @@ public unsafe DeviceCreateInfo( /// /// The newly created chain root /// A reference to the newly created chain. - public static unsafe ref DeviceCreateInfo Chain( - out DeviceCreateInfo capture) + public static unsafe ref DeviceCreateInfo Chain + ( + out DeviceCreateInfo capture + ) { capture = new DeviceCreateInfo(StructureType.DeviceCreateInfo); return ref capture; @@ -49,5 +61,12 @@ StructureType IStructuredType.StructureType() return SType = StructureType.DeviceCreateInfo; } + /// + unsafe Chain* IChainable.PNext + { + get => (Chain*) PNext; + set => PNext = value; + } + #endregion -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs index a86e8db5ea..4da9542556 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs @@ -7,4 +7,4 @@ namespace Silk.Net.Vulkan; /// convenience method. public interface IChainStart : IChainable { -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs index 7b8df844f2..098fd169bc 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs @@ -8,4 +8,5 @@ namespace Silk.Net.Vulkan; /// to a pointer to a . public interface IChainable : IStructuredType { + unsafe Chain* PNext { get; set; } } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs index aa6a7fdbc1..f34ad05399 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs @@ -13,4 +13,4 @@ public interface IStructuredType /// Retrieving the also ensures it is set to the correct value. /// StructureType StructureType(); -} \ No newline at end of file +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs index d06389fcad..def61ff87a 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs @@ -1,3 +1,4 @@ +// ReSharper disable StaticMemberInGenericType using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -26,6 +27,42 @@ IEnumerator IEnumerable.GetEnumerator() /// public abstract void Dispose(); + /// + /// Creates a new with 1 items. + /// + /// The head of the chain. + /// The chain type + /// A new with 1 items. + public static ManagedChain Create(TChain head = default) + where TChain : struct, IChainStart + { + return new(head); + } + + /// + /// Loads a new with 1 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 1 items. + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + { + return new(out errors, chain); + } + + /// + /// Loads a new with 1 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 1 items. + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + { + return new(out var _, chain); + } + /// /// Creates a new with 2 items. /// @@ -1168,6 +1205,154 @@ public static ManagedChain +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart +{ + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = HeadSize; + + private nint _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Creates a new with 1 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + + /// + /// Creates a new with 1 items. + /// + /// The head of the chain. + public ManagedChain(TChain head = default) + : this(Marshal.AllocHGlobal(MemorySize)) + { + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + HeadPtr->PNext = null; + } + + /// + /// Creates a new with 1 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) + { + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); + errors = string.Empty; + } + + /// + /// Creates a new with 1 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 2 items, by appending to + /// the end of this chain. + /// + /// Item 1. + /// Type of Item 1 + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Append(T1 item1 = default) + where T1: struct, IExtendsChain + { + return new ManagedChain(this, item1); + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + } + + /// + public override int Count => 1; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + public void Deconstruct(out TChain head) + { + head = Head; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + /// /// A safely manages the pointers of a managed structure chain. /// @@ -1177,7 +1362,27 @@ public unsafe class ManagedChain : ManagedChain where TChain : struct, IChainStart where T1 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item1Offset + Item1Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -1193,53 +1398,61 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 2 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 2 items. /// /// The head of the chain. /// Item 1. public ManagedChain(TChain head = default, T1 item1 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + Item1Ptr->PNext = null; } /// @@ -1248,43 +1461,114 @@ public ManagedChain(TChain head = default, T1 item1 = default) /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); + existingPtr->PNext = null; + } + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item1, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size); - Marshal.StructureToPtr(head, _headPtr, false); + /// + /// Creates a new with 2 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 2 items, by appending + /// to the end of this chain. + /// + /// The chain to append to. + /// Item 1. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T1 item1 = default) + : this(Marshal.AllocHGlobal(MemorySize)) + { + var previousSize = MemorySize - Item1Size; + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 1 + item1.StructureType(); + Marshal.StructureToPtr(item1, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } + + /// + /// Creates a new with 1 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + /// + /// Creates a new with 1 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T1 item1) + { + item1 = Item1; + + var newSize = MemorySize - Item1Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -1294,7 +1578,7 @@ public ManagedChain(out string errors, TChain chain) /// Item 2. /// Type of Item 2 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T2 item2 = default) where T2: struct, IExtendsChain @@ -1316,7 +1600,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, _ => throw new IndexOutOfRangeException() }; @@ -1334,13 +1619,14 @@ public void Deconstruct(out TChain head, out T1 item1) /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -1358,7 +1644,37 @@ public unsafe class ManagedChain : ManagedChain where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item2Offset + Item2Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -1374,55 +1690,67 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 3 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 3 items. /// @@ -1430,25 +1758,19 @@ public T2 Item2 /// Item 1. /// Item 2. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + Item2Ptr->PNext = null; } /// @@ -1457,68 +1779,84 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 3"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 3"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 3"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 3"); + existingPtr->PNext = null; + } + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item2, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + /// + /// Creates a new with 3 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 3 items. + /// Creates a new with 3 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 2. @@ -1526,27 +1864,53 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T2 item2 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); + var previousSize = MemorySize - Item2Size; + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 2 + item2.StructureType(); + Marshal.StructureToPtr(item2, _headPtr + previousSize, false); - var originalSize = headSize + item1Size; - var newSize = originalSize + item2Size; + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } - _headPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + /// + /// Creates a new with 2 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + /// + /// Creates a new with 2 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T2 item2) + { + item2 = Item2; - _item2Ptr = _item1Ptr + item1Size; - // Append the last structure - item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + var newSize = MemorySize - Item2Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -1556,7 +1920,7 @@ public ManagedChain(ManagedChain previous, T2 item2 = default) /// Item 3. /// Type of Item 3 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T3 item3 = default) where T3: struct, IExtendsChain @@ -1579,7 +1943,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, _ => throw new IndexOutOfRangeException() }; @@ -1600,15 +1965,15 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2) /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -1628,15 +1993,55 @@ public unsafe class ManagedChain : ManagedChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain { - private IntPtr _headPtr; - /// - /// Gets a pointer to the current head. + /// Gets the size (in bytes) of the head structure. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public static readonly int HeadSize = Marshal.SizeOf(); /// - /// Gets or sets the head of the chain. + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item3Offset + Item3Size; + + private nint _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. /// public TChain Head { @@ -1644,76 +2049,88 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 4 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 4 items. /// @@ -1722,31 +2139,23 @@ public T3 Item3 /// Item 2. /// Item 3. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + Item3Ptr->PNext = null; } /// @@ -1755,89 +2164,106 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 4"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 4"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 4"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 4"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 4"); + existingPtr->PNext = null; + } + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item3, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + /// + /// Creates a new with 4 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 4 items. + /// Creates a new with 4 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 3. @@ -1845,31 +2271,55 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T3 item3 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size; - var newSize = originalSize + item3Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item3Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 3 + item3.StructureType(); + Marshal.StructureToPtr(item3, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + /// + /// Creates a new with 3 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + /// + /// Creates a new with 3 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T3 item3) + { + item3 = Item3; - _item3Ptr = _item2Ptr + item2Size; - // Append the last structure - item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + var newSize = MemorySize - Item3Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -1879,7 +2329,7 @@ public ManagedChain(ManagedChain previous, T3 item3 = default) /// Item 4. /// Type of Item 4 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T4 item4 = default) where T4: struct, IExtendsChain @@ -1903,7 +2353,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, _ => throw new IndexOutOfRangeException() @@ -1927,17 +2378,16 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -1959,7 +2409,57 @@ public unsafe class ManagedChain : ManagedChain where T3 : struct, IExtendsChain where T4 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item4Offset + Item4Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -1975,97 +2475,109 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 5 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 5 items. /// @@ -2075,37 +2587,27 @@ public T4 Item4 /// Item 3. /// Item 4. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + Item4Ptr->PNext = null; } /// @@ -2114,110 +2616,128 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 5"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 5"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 5"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 5"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 5"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 5"); + existingPtr->PNext = null; + } + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item4, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + /// + /// Creates a new with 5 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 5 items. + /// Creates a new with 5 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 4. @@ -2225,35 +2745,57 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T4 item4 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size; - var newSize = originalSize + item4Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item4Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 4 + item4.StructureType(); + Marshal.StructureToPtr(item4, _headPtr + previousSize, false); - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + /// + /// Creates a new with 4 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + /// + /// Creates a new with 4 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T4 item4) + { + item4 = Item4; - _item4Ptr = _item3Ptr + item3Size; - // Append the last structure - item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + var newSize = MemorySize - Item4Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -2263,7 +2805,7 @@ public ManagedChain(ManagedChain previous, T4 item4 = defaul /// Item 5. /// Type of Item 5 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T5 item5 = default) where T5: struct, IExtendsChain @@ -2288,7 +2830,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -2315,19 +2858,17 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -2351,7 +2892,67 @@ public unsafe class ManagedChain : ManagedChain where T4 : struct, IExtendsChain where T5 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item5Offset + Item5Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -2367,118 +2968,130 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 6 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 6 items. /// @@ -2489,43 +3102,31 @@ public T5 Item5 /// Item 4. /// Item 5. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + Item5Ptr->PNext = null; } /// @@ -2534,131 +3135,150 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 6"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 6"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 6"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 6"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 6"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 6"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 6"); + existingPtr->PNext = null; + } + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item5, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + /// + /// Creates a new with 6 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 6 items. + /// Creates a new with 6 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 5. @@ -2666,39 +3286,59 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T5 item5 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size; - var newSize = originalSize + item5Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item5Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 5 + item5.StructureType(); + Marshal.StructureToPtr(item5, _headPtr + previousSize, false); - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + /// + /// Creates a new with 5 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + /// + /// Creates a new with 5 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T5 item5) + { + item5 = Item5; - _item5Ptr = _item4Ptr + item4Size; - // Append the last structure - item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + var newSize = MemorySize - Item5Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -2708,7 +3348,7 @@ public ManagedChain(ManagedChain previous, T5 item5 = de /// Item 6. /// Type of Item 6 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T6 item6 = default) where T6: struct, IExtendsChain @@ -2734,7 +3374,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -2764,21 +3405,18 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -2804,155 +3442,237 @@ public unsafe class ManagedChain : ManagedChain where T5 : struct, IExtendsChain where T6 : struct, IExtendsChain { - private IntPtr _headPtr; - /// - /// Gets a pointer to the current head. + /// Gets the size (in bytes) of the head structure. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public static readonly int HeadSize = Marshal.SizeOf(); /// - /// Gets or sets the head of the chain. + /// Gets the offset to the start of . /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } - - private IntPtr _item1Ptr; + public static readonly int Item1Offset = HeadSize; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public static readonly int Item1Size = Marshal.SizeOf(); /// - /// Gets or sets item #1 in the chain. + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item6Offset + Item6Size; + + private nint _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + + /// + /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 7 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 7 items. /// @@ -2964,49 +3684,35 @@ public T6 Item6 /// Item 5. /// Item 6. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + Item6Ptr->PNext = null; } /// @@ -3015,152 +3721,172 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 7"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 7"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 7"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 7"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 7"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 7"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 7"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 7"); + existingPtr->PNext = null; + } + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item6, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + /// + /// Creates a new with 7 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 7 items. + /// Creates a new with 7 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 6. @@ -3168,43 +3894,61 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T6 item6 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size; - var newSize = originalSize + item6Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item6Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 6 + item6.StructureType(); + Marshal.StructureToPtr(item6, _headPtr + previousSize, false); - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + /// + /// Creates a new with 6 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + /// + /// Creates a new with 6 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T6 item6) + { + item6 = Item6; - _item6Ptr = _item5Ptr + item5Size; - // Append the last structure - item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + var newSize = MemorySize - Item6Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -3214,7 +3958,7 @@ public ManagedChain(ManagedChain previous, T6 item6 /// Item 7. /// Type of Item 7 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T7 item7 = default) where T7: struct, IExtendsChain @@ -3241,7 +3985,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -3274,23 +4019,19 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -3318,7 +4059,87 @@ public unsafe class ManagedChain : ManagedCh where T6 : struct, IExtendsChain where T7 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item7Offset + Item7Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -3334,160 +4155,172 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item7Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; + public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. /// public T7 Item7 { - get => Unsafe.AsRef((Chain*) _item7Ptr); + get => Unsafe.AsRef(Item7Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 8 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 8 items. /// @@ -3500,55 +4333,39 @@ public T7 Item7 /// Item 6. /// Item 7. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + Item7Ptr->PNext = null; } /// @@ -3557,173 +4374,194 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 8"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 8"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 8"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 8"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 8"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 8"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); + } else { + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item7Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T7 item7 = default; - if (currentPtr is null) + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 8"); - else { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 8; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item7 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 8"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 8"); + existingPtr->PNext = null; + } + item7 = Unsafe.AsRef(existingPtr); + } } - var item7Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item7, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + /// + /// Creates a new with 8 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 8 items. + /// Creates a new with 8 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 7. @@ -3731,47 +4569,63 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T7 item7 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size; - var newSize = originalSize + item7Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item7Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 7 + item7.StructureType(); + Marshal.StructureToPtr(item7, _headPtr + previousSize, false); - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + /// + /// Creates a new with 7 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + /// + /// Creates a new with 7 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T7 item7) + { + item7 = Item7; - _item7Ptr = _item6Ptr + item6Size; - // Append the last structure - item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + var newSize = MemorySize - Item7Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -3781,7 +4635,7 @@ public ManagedChain(ManagedChain previous, T7 it /// Item 8. /// Type of Item 8 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T8 item8 = default) where T8: struct, IExtendsChain @@ -3809,7 +4663,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -3845,25 +4700,20 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -3893,197 +4743,299 @@ public unsafe class ManagedChain : Manag where T7 : struct, IExtendsChain where T8 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); /// - /// Gets a pointer to the current head. + /// Gets the offset to the start of . /// - public Chain* HeadPtr => (Chain*) _headPtr; + public static readonly int Item1Offset = HeadSize; /// - /// Gets or sets the head of the chain. + /// Gets the size (in bytes) of the Item 1. /// - public TChain Head - { - get => Unsafe.AsRef((Chain*) _headPtr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; - } - } + public static readonly int Item1Size = Marshal.SizeOf(); - private IntPtr _item1Ptr; + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public static readonly int Item2Size = Marshal.SizeOf(); /// - /// Gets or sets item #1 in the chain. + /// Gets the offset to the start of . /// - public T1 Item1 - { - get => Unsafe.AsRef((Chain*) _item1Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; - } - } - private IntPtr _item2Ptr; + public static readonly int Item3Offset = Item2Offset + Item2Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public static readonly int Item3Size = Marshal.SizeOf(); /// - /// Gets or sets item #2 in the chain. + /// Gets the offset to the start of . /// - public T2 Item2 - { - get => Unsafe.AsRef((Chain*) _item2Ptr); - set - { - value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; - } - } - private IntPtr _item3Ptr; + public static readonly int Item4Offset = Item3Offset + Item3Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public static readonly int Item4Size = Marshal.SizeOf(); /// - /// Gets or sets item #3 in the chain. + /// Gets the offset to the start of . /// - public T3 Item3 + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item8Offset + Item8Size; + + private nint _headPtr; + + /// + /// Gets a pointer to the current head. + /// + public Chain* HeadPtr => (Chain*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((Chain*) _headPtr); + set + { + value.StructureType(); + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef(Item1Ptr); + set + { + value.StructureType(); + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef(Item2Ptr); + set + { + value.StructureType(); + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Gets a pointer to the second item in the chain. + /// + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item7Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; + public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. /// public T7 Item7 { - get => Unsafe.AsRef((Chain*) _item7Ptr); + get => Unsafe.AsRef(Item7Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item8Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; + public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. /// public T8 Item8 { - get => Unsafe.AsRef((Chain*) _item8Ptr); + get => Unsafe.AsRef(Item8Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 9 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 9 items. /// @@ -4097,61 +5049,43 @@ public T8 Item8 /// Item 7. /// Item 8. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + Item8Ptr->PNext = null; } /// @@ -4160,194 +5094,216 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 9"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 9"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 9"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 9"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 9"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 9"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); + } else { + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item7Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T7 item7 = default; - if (currentPtr is null) + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 9"); - else { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 8; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item7 = Unsafe.AsRef(currentPtr); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } - var item7Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item8Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T8 item8 = default; - if (currentPtr is null) + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 9"); - else { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 9; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item8 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 9"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 9"); + existingPtr->PNext = null; + } + item8 = Unsafe.AsRef(existingPtr); + } } - var item8Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item8, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + /// + /// Creates a new with 9 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 9 items. + /// Creates a new with 9 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 8. @@ -4355,51 +5311,65 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T8 item8 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size; - var newSize = originalSize + item8Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item8Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 8 + item8.StructureType(); + Marshal.StructureToPtr(item8, _headPtr + previousSize, false); - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); + ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; + /// + /// Creates a new with 8 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; + /// + /// Creates a new with 8 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T8 item8) + { + item8 = Item8; - _item8Ptr = _item7Ptr + item7Size; - // Append the last structure - item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + var newSize = MemorySize - Item8Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -4409,7 +5379,7 @@ public ManagedChain(ManagedChain previous, T /// Item 9. /// Type of Item 9 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T9 item9 = default) where T9: struct, IExtendsChain @@ -4438,7 +5408,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -4477,27 +5448,21 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + Marshal.DestroyStructure(headPtr + Item8Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -4529,7 +5494,107 @@ public unsafe class ManagedChain : M where T8 : struct, IExtendsChain where T9 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item9Offset = Item8Offset + Item8Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item9Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item9Offset + Item9Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -4545,202 +5610,214 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item7Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; + public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. /// public T7 Item7 { - get => Unsafe.AsRef((Chain*) _item7Ptr); + get => Unsafe.AsRef(Item7Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item8Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; + public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. /// public T8 Item8 { - get => Unsafe.AsRef((Chain*) _item8Ptr); + get => Unsafe.AsRef(Item8Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item9Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; + public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. /// public T9 Item9 { - get => Unsafe.AsRef((Chain*) _item9Ptr); + get => Unsafe.AsRef(Item9Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 10 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 10 items. /// @@ -4755,67 +5832,47 @@ public T9 Item9 /// Item 8. /// Item 9. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + Item9Ptr->PNext = null; } /// @@ -4824,215 +5881,238 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 10"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 10"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 10"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 10"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 10"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 10"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); + } else { + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item7Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T7 item7 = default; - if (currentPtr is null) + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 10"); - else { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 8; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item7 = Unsafe.AsRef(currentPtr); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } - var item7Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item8Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T8 item8 = default; - if (currentPtr is null) + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 10"); - else { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 9; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item8 = Unsafe.AsRef(currentPtr); + } else { + item8 = Unsafe.AsRef(existingPtr); + } } - var item8Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item9Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T9 item9 = default; - if (currentPtr is null) + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 10"); - else { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 10; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item9 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 10"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 10"); + existingPtr->PNext = null; + } + item9 = Unsafe.AsRef(existingPtr); + } } - var item9Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item9, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + /// + /// Creates a new with 10 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 10 items. + /// Creates a new with 10 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 9. @@ -5040,55 +6120,67 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T9 item9 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size; - var newSize = originalSize + item9Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item9Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 9 + item9.StructureType(); + Marshal.StructureToPtr(item9, _headPtr + previousSize, false); - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - // Append the last structure - item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); + ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); + ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } + + /// + /// Creates a new with 9 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } + + /// + /// Creates a new with 9 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T9 item9) + { + item9 = Item9; + + var newSize = MemorySize - Item9Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -5098,7 +6190,7 @@ public ManagedChain(ManagedChain previou /// Item 10. /// Type of Item 10 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T10 item10 = default) where T10: struct, IExtendsChain @@ -5128,7 +6220,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -5170,29 +6263,22 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + Marshal.DestroyStructure(headPtr + Item8Offset); + Marshal.DestroyStructure(headPtr + Item9Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -5226,7 +6312,117 @@ public unsafe class ManagedChain where T10 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item9Offset = Item8Offset + Item8Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item9Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item10Offset = Item9Offset + Item9Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item10Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item10Offset + Item10Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -5242,223 +6438,235 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item7Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; + public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. /// public T7 Item7 { - get => Unsafe.AsRef((Chain*) _item7Ptr); + get => Unsafe.AsRef(Item7Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item8Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; + public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. /// public T8 Item8 { - get => Unsafe.AsRef((Chain*) _item8Ptr); + get => Unsafe.AsRef(Item8Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item9Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; + public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. /// public T9 Item9 { - get => Unsafe.AsRef((Chain*) _item9Ptr); + get => Unsafe.AsRef(Item9Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item10Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; + public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. /// public T10 Item10 { - get => Unsafe.AsRef((Chain*) _item10Ptr); + get => Unsafe.AsRef(Item10Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 11 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 11 items. /// @@ -5474,73 +6682,51 @@ public T10 Item10 /// Item 9. /// Item 10. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + Item10Ptr->PNext = null; } /// @@ -5549,236 +6735,260 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 11"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 11"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 11"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 11"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 11"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 11"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); + } else { + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item7Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T7 item7 = default; - if (currentPtr is null) + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 11"); - else { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 8; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item7 = Unsafe.AsRef(currentPtr); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } - var item7Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item8Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T8 item8 = default; - if (currentPtr is null) + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 11"); - else { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 9; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item8 = Unsafe.AsRef(currentPtr); + } else { + item8 = Unsafe.AsRef(existingPtr); + } } - var item8Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item9Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T9 item9 = default; - if (currentPtr is null) + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 11"); - else { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 10; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item9 = Unsafe.AsRef(currentPtr); + } else { + item9 = Unsafe.AsRef(existingPtr); + } } - var item9Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item9, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item10Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T10 item10 = default; - if (currentPtr is null) + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 11"); - else { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 11; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item10 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 11"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 11"); + existingPtr->PNext = null; + } + item10 = Unsafe.AsRef(existingPtr); + } } - var item10Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item10, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + /// + /// Creates a new with 11 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 11 items. + /// Creates a new with 11 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 10. @@ -5786,59 +6996,69 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T10 item10 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size; - var newSize = originalSize + item10Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item10Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 10 + item10.StructureType(); + Marshal.StructureToPtr(item10, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); + ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); + ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); + ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } + + /// + /// Creates a new with 10 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + /// + /// Creates a new with 10 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T10 item10) + { + item10 = Item10; - _item10Ptr = _item9Ptr + item9Size; - // Append the last structure - item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + var newSize = MemorySize - Item10Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -5848,7 +7068,7 @@ public ManagedChain(ManagedChain pre /// Item 11. /// Type of Item 11 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T11 item11 = default) where T11: struct, IExtendsChain @@ -5879,7 +7099,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -5924,31 +7145,23 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + Marshal.DestroyStructure(headPtr + Item8Offset); + Marshal.DestroyStructure(headPtr + Item9Offset); + Marshal.DestroyStructure(headPtr + Item10Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -5984,7 +7197,127 @@ public unsafe class ManagedChain where T11 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item9Offset = Item8Offset + Item8Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item9Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item10Offset = Item9Offset + Item9Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item10Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item11Offset = Item10Offset + Item10Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item11Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item11Offset + Item11Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -6000,244 +7333,256 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item7Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; + public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. /// public T7 Item7 { - get => Unsafe.AsRef((Chain*) _item7Ptr); + get => Unsafe.AsRef(Item7Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item8Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; + public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. /// public T8 Item8 { - get => Unsafe.AsRef((Chain*) _item8Ptr); + get => Unsafe.AsRef(Item8Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item9Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; + public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. /// public T9 Item9 { - get => Unsafe.AsRef((Chain*) _item9Ptr); + get => Unsafe.AsRef(Item9Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item10Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; + public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. /// public T10 Item10 { - get => Unsafe.AsRef((Chain*) _item10Ptr); + get => Unsafe.AsRef(Item10Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item11Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; + public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. /// public T11 Item11 { - get => Unsafe.AsRef((Chain*) _item11Ptr); + get => Unsafe.AsRef(Item11Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 12 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 12 items. /// @@ -6254,79 +7599,55 @@ public T11 Item11 /// Item 10. /// Item 11. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + Item11Ptr->PNext = null; } /// @@ -6335,257 +7656,282 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 12"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 12"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 12"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 12"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 12"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 12"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); + } else { + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item7Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T7 item7 = default; - if (currentPtr is null) + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 12"); - else { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 8; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item7 = Unsafe.AsRef(currentPtr); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } - var item7Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item8Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T8 item8 = default; - if (currentPtr is null) + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 12"); - else { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 9; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item8 = Unsafe.AsRef(currentPtr); + } else { + item8 = Unsafe.AsRef(existingPtr); + } } - var item8Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item9Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T9 item9 = default; - if (currentPtr is null) + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 12"); - else { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 10; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item9 = Unsafe.AsRef(currentPtr); + } else { + item9 = Unsafe.AsRef(existingPtr); + } } - var item9Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item9, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item10Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T10 item10 = default; - if (currentPtr is null) + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 12"); - else { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 11; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item10 = Unsafe.AsRef(currentPtr); + } else { + item10 = Unsafe.AsRef(existingPtr); + } } - var item10Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item10, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item11Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T11 item11 = default; - if (currentPtr is null) + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 12"); - else { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 12; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item11 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 12"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 12"); + existingPtr->PNext = null; + } + item11 = Unsafe.AsRef(existingPtr); + } } - var item11Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item11, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - } + } /// - /// Creates a new with 12 items. + /// Creates a new with 12 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 12 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 11. @@ -6593,63 +7939,71 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T11 item11 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size; - var newSize = originalSize + item11Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item11Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 11 + item11.StructureType(); + Marshal.StructureToPtr(item11, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); + ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); + ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); + ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); + ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } + + /// + /// Creates a new with 11 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + /// + /// Creates a new with 11 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T11 item11) + { + item11 = Item11; - _item11Ptr = _item10Ptr + item10Size; - // Append the last structure - item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + var newSize = MemorySize - Item11Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -6659,7 +8013,7 @@ public ManagedChain(ManagedChainItem 12. /// Type of Item 12 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T12 item12 = default) where T12: struct, IExtendsChain @@ -6691,7 +8045,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -6739,33 +8094,24 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + Marshal.DestroyStructure(headPtr + Item8Offset); + Marshal.DestroyStructure(headPtr + Item9Offset); + Marshal.DestroyStructure(headPtr + Item10Offset); + Marshal.DestroyStructure(headPtr + Item11Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -6803,7 +8149,137 @@ public unsafe class ManagedChain where T12 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item9Offset = Item8Offset + Item8Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item9Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item10Offset = Item9Offset + Item9Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item10Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item11Offset = Item10Offset + Item10Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item11Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item12Offset = Item11Offset + Item11Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item12Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item12Offset + Item12Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -6819,265 +8295,277 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item7Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; + public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. /// public T7 Item7 { - get => Unsafe.AsRef((Chain*) _item7Ptr); + get => Unsafe.AsRef(Item7Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item8Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; + public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. /// public T8 Item8 { - get => Unsafe.AsRef((Chain*) _item8Ptr); + get => Unsafe.AsRef(Item8Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item9Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; + public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. /// public T9 Item9 { - get => Unsafe.AsRef((Chain*) _item9Ptr); + get => Unsafe.AsRef(Item9Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item10Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; + public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. /// public T10 Item10 { - get => Unsafe.AsRef((Chain*) _item10Ptr); + get => Unsafe.AsRef(Item10Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item11Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; + public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. /// public T11 Item11 { - get => Unsafe.AsRef((Chain*) _item11Ptr); + get => Unsafe.AsRef(Item11Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item12Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item12Ptr => (Chain*) _item12Ptr; + public Chain* Item12Ptr => (Chain*) (_headPtr + Item12Offset); /// /// Gets or sets item #12 in the chain. /// public T12 Item12 { - get => Unsafe.AsRef((Chain*) _item12Ptr); + get => Unsafe.AsRef(Item12Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item12Ptr)->PNext; - Marshal.StructureToPtr(value, _item12Ptr, true); - ((Chain*) _item12Ptr)->PNext = nextPtr; + var ptr = Item12Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 13 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 13 items. /// @@ -7095,85 +8583,59 @@ public T12 Item12 /// Item 11. /// Item 12. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + itemPtr = Item12Ptr; item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + Marshal.StructureToPtr(item12, (nint)itemPtr, false); + Item11Ptr->PNext = itemPtr; + Item12Ptr->PNext = null; } /// @@ -7182,278 +8644,304 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 13"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 13"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 13"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 13"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 13"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 13"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); + } else { + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item7Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T7 item7 = default; - if (currentPtr is null) + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 13"); - else { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 8; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item7 = Unsafe.AsRef(currentPtr); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } - var item7Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item8Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T8 item8 = default; - if (currentPtr is null) + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 13"); - else { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 9; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item8 = Unsafe.AsRef(currentPtr); + } else { + item8 = Unsafe.AsRef(existingPtr); + } } - var item8Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item9Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T9 item9 = default; - if (currentPtr is null) + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 13"); - else { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 10; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item9 = Unsafe.AsRef(currentPtr); + } else { + item9 = Unsafe.AsRef(existingPtr); + } } - var item9Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item9, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item10Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T10 item10 = default; - if (currentPtr is null) + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 13"); - else { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 11; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item10 = Unsafe.AsRef(currentPtr); + } else { + item10 = Unsafe.AsRef(existingPtr); + } } - var item10Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item10, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item11Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T11 item11 = default; - if (currentPtr is null) + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 13"); - else { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 12; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item11 = Unsafe.AsRef(currentPtr); + } else { + item11 = Unsafe.AsRef(existingPtr); + } } - var item11Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item11, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item12Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T12 item12 = default; - if (currentPtr is null) + expectedStructureType = item12.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 13"); - else { - expectedStructureType = item12.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 13; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item12 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 13"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 13"); + existingPtr->PNext = null; + } + item12 = Unsafe.AsRef(existingPtr); + } } - var item12Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item12, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; } /// - /// Creates a new with 13 items. + /// Creates a new with 13 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 13 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 12. @@ -7461,67 +8949,73 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T12 item12 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size; - var newSize = originalSize + item12Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item12Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 12 + item12.StructureType(); + Marshal.StructureToPtr(item12, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); + ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); + ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); + ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); + ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); + ((Chain*)(_headPtr + Item11Offset))->PNext = (Chain*) (_headPtr + Item12Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } + + /// + /// Creates a new with 12 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item11Ptr = _item10Ptr + item10Size; - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + /// + /// Creates a new with 12 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T12 item12) + { + item12 = Item12; - _item12Ptr = _item11Ptr + item11Size; - // Append the last structure - item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + var newSize = MemorySize - Item12Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + ((Chain*)(newHeadPtr + Item11Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -7531,7 +9025,7 @@ public ManagedChain(ManagedChainItem 13. /// Type of Item 13 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T13 item13 = default) where T13: struct, IExtendsChain @@ -7564,7 +9058,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -7612,78 +9107,208 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item item12 = Item12; } - /// - public override void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + Marshal.DestroyStructure(headPtr + Item8Offset); + Marshal.DestroyStructure(headPtr + Item9Offset); + Marshal.DestroyStructure(headPtr + Item10Offset); + Marshal.DestroyStructure(headPtr + Item11Offset); + Marshal.DestroyStructure(headPtr + Item12Offset); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +/// Type of Item 13. +public unsafe class ManagedChain : ManagedChain + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain +{ + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item9Offset = Item8Offset + Item8Size; - // Destroy all structures - Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); - var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item12Ptr); + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item9Size = Marshal.SizeOf(); - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} + /// + /// Gets the offset to the start of . + /// + public static readonly int Item10Offset = Item9Offset + Item9Size; -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -/// Type of Item 9. -/// Type of Item 10. -/// Type of Item 11. -/// Type of Item 12. -/// Type of Item 13. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain -{ - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item10Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item11Offset = Item10Offset + Item10Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item11Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item12Offset = Item11Offset + Item11Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item12Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item13Offset = Item12Offset + Item12Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item13Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item13Offset + Item13Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -7699,286 +9324,298 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item7Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; + public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. /// public T7 Item7 { - get => Unsafe.AsRef((Chain*) _item7Ptr); + get => Unsafe.AsRef(Item7Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item8Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; + public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. /// public T8 Item8 { - get => Unsafe.AsRef((Chain*) _item8Ptr); + get => Unsafe.AsRef(Item8Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item9Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; + public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. /// public T9 Item9 { - get => Unsafe.AsRef((Chain*) _item9Ptr); + get => Unsafe.AsRef(Item9Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item10Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; + public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. /// public T10 Item10 { - get => Unsafe.AsRef((Chain*) _item10Ptr); + get => Unsafe.AsRef(Item10Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item11Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; + public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. /// public T11 Item11 { - get => Unsafe.AsRef((Chain*) _item11Ptr); + get => Unsafe.AsRef(Item11Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item12Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item12Ptr => (Chain*) _item12Ptr; + public Chain* Item12Ptr => (Chain*) (_headPtr + Item12Offset); /// /// Gets or sets item #12 in the chain. /// public T12 Item12 { - get => Unsafe.AsRef((Chain*) _item12Ptr); + get => Unsafe.AsRef(Item12Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item12Ptr)->PNext; - Marshal.StructureToPtr(value, _item12Ptr, true); - ((Chain*) _item12Ptr)->PNext = nextPtr; + var ptr = Item12Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item13Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item13Ptr => (Chain*) _item13Ptr; + public Chain* Item13Ptr => (Chain*) (_headPtr + Item13Offset); /// /// Gets or sets item #13 in the chain. /// public T13 Item13 { - get => Unsafe.AsRef((Chain*) _item13Ptr); + get => Unsafe.AsRef(Item13Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item13Ptr)->PNext; - Marshal.StructureToPtr(value, _item13Ptr, true); - ((Chain*) _item13Ptr)->PNext = nextPtr; + var ptr = Item13Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 14 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 14 items. /// @@ -7997,91 +9634,63 @@ public T13 Item13 /// Item 12. /// Item 13. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + itemPtr = Item12Ptr; item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; + Marshal.StructureToPtr(item12, (nint)itemPtr, false); + Item11Ptr->PNext = itemPtr; + itemPtr = Item13Ptr; item13.StructureType(); - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + Marshal.StructureToPtr(item13, (nint)itemPtr, false); + Item12Ptr->PNext = itemPtr; + Item13Ptr->PNext = null; } /// @@ -8090,299 +9699,326 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 14"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 14"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 14"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 14"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 14"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 14"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); + } else { + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item7Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T7 item7 = default; - if (currentPtr is null) + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 14"); - else { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 8; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item7 = Unsafe.AsRef(currentPtr); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } - var item7Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item8Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T8 item8 = default; - if (currentPtr is null) + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 14"); - else { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 9; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item8 = Unsafe.AsRef(currentPtr); + } else { + item8 = Unsafe.AsRef(existingPtr); + } } - var item8Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item9Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T9 item9 = default; - if (currentPtr is null) + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 14"); - else { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 10; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item9 = Unsafe.AsRef(currentPtr); + } else { + item9 = Unsafe.AsRef(existingPtr); + } } - var item9Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item9, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item10Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T10 item10 = default; - if (currentPtr is null) + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 14"); - else { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 11; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item10 = Unsafe.AsRef(currentPtr); + } else { + item10 = Unsafe.AsRef(existingPtr); + } } - var item10Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item10, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item11Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T11 item11 = default; - if (currentPtr is null) + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 14"); - else { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 12; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item11 = Unsafe.AsRef(currentPtr); + } else { + item11 = Unsafe.AsRef(existingPtr); + } } - var item11Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item11, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item12Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T12 item12 = default; - if (currentPtr is null) + expectedStructureType = item12.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 14"); - else { - expectedStructureType = item12.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 13; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item12 = Unsafe.AsRef(currentPtr); + } else { + item12 = Unsafe.AsRef(existingPtr); + } } - var item12Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item12, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item13Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T13 item13 = default; - if (currentPtr is null) + expectedStructureType = item13.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 14"); - else { - expectedStructureType = item13.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 14; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item13 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 14"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 14"); + existingPtr->PNext = null; + } + item13 = Unsafe.AsRef(existingPtr); + } } - var item13Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item13, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; } /// - /// Creates a new with 14 items. + /// Creates a new with 14 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); + ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 14 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 13. @@ -8390,71 +10026,75 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T13 item13 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size; - var newSize = originalSize + item13Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item13Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 13 + item13.StructureType(); + Marshal.StructureToPtr(item13, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); + ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); + ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); + ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); + ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); + ((Chain*)(_headPtr + Item11Offset))->PNext = (Chain*) (_headPtr + Item12Offset); + ((Chain*)(_headPtr + Item12Offset))->PNext = (Chain*) (_headPtr + Item13Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } + + /// + /// Creates a new with 13 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item12Ptr = _item11Ptr + item11Size; - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + /// + /// Creates a new with 13 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T13 item13) + { + item13 = Item13; - _item13Ptr = _item12Ptr + item12Size; - // Append the last structure - item13.StructureType(); - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + var newSize = MemorySize - Item13Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); + ((Chain*)(newHeadPtr + Item12Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -8464,7 +10104,7 @@ public ManagedChain(ManagedChainItem 14. /// Type of Item 14 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T14 item14 = default) where T14: struct, IExtendsChain @@ -8498,7 +10138,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -8552,37 +10193,26 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); - var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item12Ptr); - var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item13Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + Marshal.DestroyStructure(headPtr + Item8Offset); + Marshal.DestroyStructure(headPtr + Item9Offset); + Marshal.DestroyStructure(headPtr + Item10Offset); + Marshal.DestroyStructure(headPtr + Item11Offset); + Marshal.DestroyStructure(headPtr + Item12Offset); + Marshal.DestroyStructure(headPtr + Item13Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -8624,7 +10254,157 @@ public unsafe class ManagedChain where T14 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item9Offset = Item8Offset + Item8Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item9Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item10Offset = Item9Offset + Item9Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item10Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item11Offset = Item10Offset + Item10Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item11Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item12Offset = Item11Offset + Item11Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item12Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item13Offset = Item12Offset + Item12Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item13Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item14Offset = Item13Offset + Item13Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item14Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item14Offset + Item14Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -8640,307 +10420,319 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item7Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; + public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. /// public T7 Item7 { - get => Unsafe.AsRef((Chain*) _item7Ptr); + get => Unsafe.AsRef(Item7Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item8Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; + public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. /// public T8 Item8 { - get => Unsafe.AsRef((Chain*) _item8Ptr); + get => Unsafe.AsRef(Item8Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item9Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; + public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. /// public T9 Item9 { - get => Unsafe.AsRef((Chain*) _item9Ptr); + get => Unsafe.AsRef(Item9Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item10Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; + public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. /// public T10 Item10 { - get => Unsafe.AsRef((Chain*) _item10Ptr); + get => Unsafe.AsRef(Item10Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item11Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; + public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. /// public T11 Item11 { - get => Unsafe.AsRef((Chain*) _item11Ptr); + get => Unsafe.AsRef(Item11Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item12Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item12Ptr => (Chain*) _item12Ptr; + public Chain* Item12Ptr => (Chain*) (_headPtr + Item12Offset); /// /// Gets or sets item #12 in the chain. /// public T12 Item12 { - get => Unsafe.AsRef((Chain*) _item12Ptr); + get => Unsafe.AsRef(Item12Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item12Ptr)->PNext; - Marshal.StructureToPtr(value, _item12Ptr, true); - ((Chain*) _item12Ptr)->PNext = nextPtr; + var ptr = Item12Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item13Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item13Ptr => (Chain*) _item13Ptr; + public Chain* Item13Ptr => (Chain*) (_headPtr + Item13Offset); /// /// Gets or sets item #13 in the chain. /// public T13 Item13 { - get => Unsafe.AsRef((Chain*) _item13Ptr); + get => Unsafe.AsRef(Item13Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item13Ptr)->PNext; - Marshal.StructureToPtr(value, _item13Ptr, true); - ((Chain*) _item13Ptr)->PNext = nextPtr; + var ptr = Item13Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item14Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item14Ptr => (Chain*) _item14Ptr; + public Chain* Item14Ptr => (Chain*) (_headPtr + Item14Offset); /// /// Gets or sets item #14 in the chain. /// public T14 Item14 { - get => Unsafe.AsRef((Chain*) _item14Ptr); + get => Unsafe.AsRef(Item14Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item14Ptr)->PNext; - Marshal.StructureToPtr(value, _item14Ptr, true); - ((Chain*) _item14Ptr)->PNext = nextPtr; + var ptr = Item14Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 15 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 15 items. /// @@ -8960,97 +10752,67 @@ public T14 Item14 /// Item 13. /// Item 14. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - var item14Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + itemPtr = Item12Ptr; item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; + Marshal.StructureToPtr(item12, (nint)itemPtr, false); + Item11Ptr->PNext = itemPtr; + itemPtr = Item13Ptr; item13.StructureType(); - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; + Marshal.StructureToPtr(item13, (nint)itemPtr, false); + Item12Ptr->PNext = itemPtr; + itemPtr = Item14Ptr; item14.StructureType(); - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + Marshal.StructureToPtr(item14, (nint)itemPtr, false); + Item13Ptr->PNext = itemPtr; + Item14Ptr->PNext = null; } /// @@ -9059,320 +10821,348 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 15"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 15"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 15"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 15"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 15"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 15"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); + } else { + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item7Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T7 item7 = default; - if (currentPtr is null) + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 15"); - else { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 8; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item7 = Unsafe.AsRef(currentPtr); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } - var item7Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item8Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T8 item8 = default; - if (currentPtr is null) + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 15"); - else { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 9; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item8 = Unsafe.AsRef(currentPtr); + } else { + item8 = Unsafe.AsRef(existingPtr); + } } - var item8Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item9Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T9 item9 = default; - if (currentPtr is null) + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 15"); - else { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 10; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item9 = Unsafe.AsRef(currentPtr); + } else { + item9 = Unsafe.AsRef(existingPtr); + } } - var item9Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item9, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item10Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T10 item10 = default; - if (currentPtr is null) + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 15"); - else { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 11; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item10 = Unsafe.AsRef(currentPtr); + } else { + item10 = Unsafe.AsRef(existingPtr); + } } - var item10Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item10, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item11Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T11 item11 = default; - if (currentPtr is null) + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 15"); - else { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 12; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item11 = Unsafe.AsRef(currentPtr); + } else { + item11 = Unsafe.AsRef(existingPtr); + } } - var item11Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item11, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item12Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T12 item12 = default; - if (currentPtr is null) + expectedStructureType = item12.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 15"); - else { - expectedStructureType = item12.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 13; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item12 = Unsafe.AsRef(currentPtr); + } else { + item12 = Unsafe.AsRef(existingPtr); + } } - var item12Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item12, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item13Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T13 item13 = default; - if (currentPtr is null) + expectedStructureType = item13.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 15"); - else { - expectedStructureType = item13.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 14; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item13 = Unsafe.AsRef(currentPtr); + } else { + item13 = Unsafe.AsRef(existingPtr); + } } - var item13Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item13, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item14Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T14 item14 = default; - if (currentPtr is null) + expectedStructureType = item14.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 15"); - else { - expectedStructureType = item14.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 15; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item14 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 15"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 15"); + existingPtr->PNext = null; + } + item14 = Unsafe.AsRef(existingPtr); + } } - var item14Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item14, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; } /// - /// Creates a new with 15 items. + /// Creates a new with 15 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); + ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); + ((Chain*)(newHeadPtr + Item13Offset))->PNext = (Chain*) (newHeadPtr + Item14Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 15 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 14. @@ -9380,75 +11170,77 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T14 item14 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - var item14Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size; - var newSize = originalSize + item14Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item14Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 14 + item14.StructureType(); + Marshal.StructureToPtr(item14, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); + ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); + ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); + ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); + ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); + ((Chain*)(_headPtr + Item11Offset))->PNext = (Chain*) (_headPtr + Item12Offset); + ((Chain*)(_headPtr + Item12Offset))->PNext = (Chain*) (_headPtr + Item13Offset); + ((Chain*)(_headPtr + Item13Offset))->PNext = (Chain*) (_headPtr + Item14Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } + + /// + /// Creates a new with 14 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item13Ptr = _item12Ptr + item12Size; - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + /// + /// Creates a new with 14 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T14 item14) + { + item14 = Item14; - _item14Ptr = _item13Ptr + item13Size; - // Append the last structure - item14.StructureType(); - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + var newSize = MemorySize - Item14Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); + ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); + ((Chain*)(newHeadPtr + Item13Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -9458,7 +11250,7 @@ public ManagedChain(ManagedChainItem 15. /// Type of Item 15 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T15 item15 = default) where T15: struct, IExtendsChain @@ -9493,7 +11285,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -9550,39 +11343,27 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); - var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item12Ptr); - var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item13Ptr); - var item14Ptr = Interlocked.Exchange(ref _item14Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item14Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + Marshal.DestroyStructure(headPtr + Item8Offset); + Marshal.DestroyStructure(headPtr + Item9Offset); + Marshal.DestroyStructure(headPtr + Item10Offset); + Marshal.DestroyStructure(headPtr + Item11Offset); + Marshal.DestroyStructure(headPtr + Item12Offset); + Marshal.DestroyStructure(headPtr + Item13Offset); + Marshal.DestroyStructure(headPtr + Item14Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -9626,7 +11407,167 @@ public unsafe class ManagedChain where T15 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item4Offset = Item3Offset + Item3Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item9Offset = Item8Offset + Item8Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item9Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item10Offset = Item9Offset + Item9Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item10Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item11Offset = Item10Offset + Item10Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item11Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item12Offset = Item11Offset + Item11Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item12Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item13Offset = Item12Offset + Item12Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item13Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item14Offset = Item13Offset + Item13Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item14Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item15Offset = Item14Offset + Item14Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item15Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item15Offset + Item15Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -9642,328 +11583,340 @@ public TChain Head set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item2Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) _item2Ptr; + public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. /// public T2 Item2 { - get => Unsafe.AsRef((Chain*) _item2Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item2Ptr)->PNext; - Marshal.StructureToPtr(value, _item2Ptr, true); - ((Chain*) _item2Ptr)->PNext = nextPtr; + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item3Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) _item3Ptr; + public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. /// public T3 Item3 { - get => Unsafe.AsRef((Chain*) _item3Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item3Ptr)->PNext; - Marshal.StructureToPtr(value, _item3Ptr, true); - ((Chain*) _item3Ptr)->PNext = nextPtr; + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item4Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) _item4Ptr; + public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. /// public T4 Item4 { - get => Unsafe.AsRef((Chain*) _item4Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item4Ptr)->PNext; - Marshal.StructureToPtr(value, _item4Ptr, true); - ((Chain*) _item4Ptr)->PNext = nextPtr; + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item5Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) _item5Ptr; + public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. /// public T5 Item5 { - get => Unsafe.AsRef((Chain*) _item5Ptr); + get => Unsafe.AsRef(Item5Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item5Ptr)->PNext; - Marshal.StructureToPtr(value, _item5Ptr, true); - ((Chain*) _item5Ptr)->PNext = nextPtr; + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item6Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) _item6Ptr; + public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. /// public T6 Item6 { - get => Unsafe.AsRef((Chain*) _item6Ptr); + get => Unsafe.AsRef(Item6Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item6Ptr)->PNext; - Marshal.StructureToPtr(value, _item6Ptr, true); - ((Chain*) _item6Ptr)->PNext = nextPtr; + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item7Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) _item7Ptr; + public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. /// public T7 Item7 { - get => Unsafe.AsRef((Chain*) _item7Ptr); + get => Unsafe.AsRef(Item7Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item7Ptr)->PNext; - Marshal.StructureToPtr(value, _item7Ptr, true); - ((Chain*) _item7Ptr)->PNext = nextPtr; + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item8Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) _item8Ptr; + public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. /// public T8 Item8 { - get => Unsafe.AsRef((Chain*) _item8Ptr); + get => Unsafe.AsRef(Item8Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item8Ptr)->PNext; - Marshal.StructureToPtr(value, _item8Ptr, true); - ((Chain*) _item8Ptr)->PNext = nextPtr; + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item9Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) _item9Ptr; + public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. /// public T9 Item9 { - get => Unsafe.AsRef((Chain*) _item9Ptr); + get => Unsafe.AsRef(Item9Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item9Ptr)->PNext; - Marshal.StructureToPtr(value, _item9Ptr, true); - ((Chain*) _item9Ptr)->PNext = nextPtr; + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item10Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) _item10Ptr; + public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. /// public T10 Item10 { - get => Unsafe.AsRef((Chain*) _item10Ptr); + get => Unsafe.AsRef(Item10Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item10Ptr)->PNext; - Marshal.StructureToPtr(value, _item10Ptr, true); - ((Chain*) _item10Ptr)->PNext = nextPtr; + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item11Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) _item11Ptr; + public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. /// public T11 Item11 { - get => Unsafe.AsRef((Chain*) _item11Ptr); + get => Unsafe.AsRef(Item11Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item11Ptr)->PNext; - Marshal.StructureToPtr(value, _item11Ptr, true); - ((Chain*) _item11Ptr)->PNext = nextPtr; + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item12Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item12Ptr => (Chain*) _item12Ptr; + public Chain* Item12Ptr => (Chain*) (_headPtr + Item12Offset); /// /// Gets or sets item #12 in the chain. /// public T12 Item12 { - get => Unsafe.AsRef((Chain*) _item12Ptr); + get => Unsafe.AsRef(Item12Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item12Ptr)->PNext; - Marshal.StructureToPtr(value, _item12Ptr, true); - ((Chain*) _item12Ptr)->PNext = nextPtr; + var ptr = Item12Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item13Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item13Ptr => (Chain*) _item13Ptr; + public Chain* Item13Ptr => (Chain*) (_headPtr + Item13Offset); /// /// Gets or sets item #13 in the chain. /// public T13 Item13 { - get => Unsafe.AsRef((Chain*) _item13Ptr); + get => Unsafe.AsRef(Item13Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item13Ptr)->PNext; - Marshal.StructureToPtr(value, _item13Ptr, true); - ((Chain*) _item13Ptr)->PNext = nextPtr; + var ptr = Item13Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item14Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item14Ptr => (Chain*) _item14Ptr; + public Chain* Item14Ptr => (Chain*) (_headPtr + Item14Offset); /// /// Gets or sets item #14 in the chain. /// public T14 Item14 { - get => Unsafe.AsRef((Chain*) _item14Ptr); + get => Unsafe.AsRef(Item14Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item14Ptr)->PNext; - Marshal.StructureToPtr(value, _item14Ptr, true); - ((Chain*) _item14Ptr)->PNext = nextPtr; + var ptr = Item14Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } - private IntPtr _item15Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item15Ptr => (Chain*) _item15Ptr; + public Chain* Item15Ptr => (Chain*) (_headPtr + Item15Offset); /// /// Gets or sets item #15 in the chain. /// public T15 Item15 { - get => Unsafe.AsRef((Chain*) _item15Ptr); + get => Unsafe.AsRef(Item15Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item15Ptr)->PNext; - Marshal.StructureToPtr(value, _item15Ptr, true); - ((Chain*) _item15Ptr)->PNext = nextPtr; + var ptr = Item15Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 16 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 16 items. /// @@ -9984,103 +11937,71 @@ public T15 Item15 /// Item 14. /// Item 15. public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - var item14Size = Marshal.SizeOf(); - var item15Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size + item15Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; item2.StructureType(); - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; item3.StructureType(); - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; item4.StructureType(); - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; item5.StructureType(); - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; item6.StructureType(); - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; item7.StructureType(); - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; item8.StructureType(); - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; item9.StructureType(); - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; item10.StructureType(); - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; item11.StructureType(); - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + itemPtr = Item12Ptr; item12.StructureType(); - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; + Marshal.StructureToPtr(item12, (nint)itemPtr, false); + Item11Ptr->PNext = itemPtr; + itemPtr = Item13Ptr; item13.StructureType(); - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; + Marshal.StructureToPtr(item13, (nint)itemPtr, false); + Item12Ptr->PNext = itemPtr; + itemPtr = Item14Ptr; item14.StructureType(); - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; - - _item15Ptr = _item14Ptr + item14Size; + Marshal.StructureToPtr(item14, (nint)itemPtr, false); + Item13Ptr->PNext = itemPtr; + itemPtr = Item15Ptr; item15.StructureType(); - Marshal.StructureToPtr(item15, _item15Ptr, false); - ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; + Marshal.StructureToPtr(item15, (nint)itemPtr, false); + Item14Ptr->PNext = itemPtr; + Item15Ptr->PNext = null; } /// @@ -10089,341 +12010,370 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 16"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); + } else { + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item2Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T2 item2 = default; - if (currentPtr is null) + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 16"); - else { - expectedStructureType = item2.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 3; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item2 = Unsafe.AsRef(currentPtr); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - var item2Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item3Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T3 item3 = default; - if (currentPtr is null) + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 16"); - else { - expectedStructureType = item3.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 4; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item3 = Unsafe.AsRef(currentPtr); + } else { + item3 = Unsafe.AsRef(existingPtr); + } } - var item3Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item4Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T4 item4 = default; - if (currentPtr is null) + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 16"); - else { - expectedStructureType = item4.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 5; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item4 = Unsafe.AsRef(currentPtr); + } else { + item4 = Unsafe.AsRef(existingPtr); + } } - var item4Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item5Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T5 item5 = default; - if (currentPtr is null) + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 16"); - else { - expectedStructureType = item5.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 6; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item5 = Unsafe.AsRef(currentPtr); + } else { + item5 = Unsafe.AsRef(existingPtr); + } } - var item5Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item6Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T6 item6 = default; - if (currentPtr is null) + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 16"); - else { - expectedStructureType = item6.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 7; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item6 = Unsafe.AsRef(currentPtr); + } else { + item6 = Unsafe.AsRef(existingPtr); + } } - var item6Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item7Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T7 item7 = default; - if (currentPtr is null) + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 16"); - else { - expectedStructureType = item7.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 8; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item7 = Unsafe.AsRef(currentPtr); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } - var item7Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item8Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T8 item8 = default; - if (currentPtr is null) + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 16"); - else { - expectedStructureType = item8.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 9; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item8 = Unsafe.AsRef(currentPtr); + } else { + item8 = Unsafe.AsRef(existingPtr); + } } - var item8Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item9Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T9 item9 = default; - if (currentPtr is null) + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 16"); - else { - expectedStructureType = item9.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 10; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item9 = Unsafe.AsRef(currentPtr); + } else { + item9 = Unsafe.AsRef(existingPtr); + } } - var item9Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item9, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item10Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T10 item10 = default; - if (currentPtr is null) + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 16"); - else { - expectedStructureType = item10.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 11; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item10 = Unsafe.AsRef(currentPtr); + } else { + item10 = Unsafe.AsRef(existingPtr); + } } - var item10Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item10, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item11Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T11 item11 = default; - if (currentPtr is null) + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 16"); - else { - expectedStructureType = item11.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 12; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item11 = Unsafe.AsRef(currentPtr); + } else { + item11 = Unsafe.AsRef(existingPtr); + } } - var item11Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item11, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item12Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T12 item12 = default; - if (currentPtr is null) + expectedStructureType = item12.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 16"); - else { - expectedStructureType = item12.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 13; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item12 = Unsafe.AsRef(currentPtr); + } else { + item12 = Unsafe.AsRef(existingPtr); + } } - var item12Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item12, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item13Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T13 item13 = default; - if (currentPtr is null) + expectedStructureType = item13.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 16"); - else { - expectedStructureType = item13.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 14; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item13 = Unsafe.AsRef(currentPtr); + } else { + item13 = Unsafe.AsRef(existingPtr); + } } - var item13Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item13, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item14Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T14 item14 = default; - if (currentPtr is null) + expectedStructureType = item14.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 16"); - else { - expectedStructureType = item14.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 15; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item14 = Unsafe.AsRef(currentPtr); + } else { + item14 = Unsafe.AsRef(existingPtr); + } } - var item14Size = Marshal.SizeOf(); + Marshal.StructureToPtr(item14, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item15Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T15 item15 = default; - if (currentPtr is null) + expectedStructureType = item15.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 15, expected length 16"); - else { - expectedStructureType = item15.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 16; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item15 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 16"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 16"); + existingPtr->PNext = null; + } + item15 = Unsafe.AsRef(existingPtr); + } } - var item15Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item15, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size + item15Size); - Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - Marshal.StructureToPtr(item2, _item2Ptr, false); - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - Marshal.StructureToPtr(item3, _item3Ptr, false); - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - Marshal.StructureToPtr(item4, _item4Ptr, false); - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - Marshal.StructureToPtr(item5, _item5Ptr, false); - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - Marshal.StructureToPtr(item6, _item6Ptr, false); - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - Marshal.StructureToPtr(item7, _item7Ptr, false); - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - Marshal.StructureToPtr(item8, _item8Ptr, false); - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - Marshal.StructureToPtr(item9, _item9Ptr, false); - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - Marshal.StructureToPtr(item10, _item10Ptr, false); - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - Marshal.StructureToPtr(item11, _item11Ptr, false); - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - Marshal.StructureToPtr(item12, _item12Ptr, false); - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - Marshal.StructureToPtr(item13, _item13Ptr, false); - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; - - _item14Ptr = _item13Ptr + item13Size; - Marshal.StructureToPtr(item14, _item14Ptr, false); - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; - - _item15Ptr = _item14Ptr + item14Size; - Marshal.StructureToPtr(item15, _item15Ptr, false); - ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; } /// - /// Creates a new with 16 items. + /// Creates a new with 16 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); + ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); + ((Chain*)(newHeadPtr + Item13Offset))->PNext = (Chain*) (newHeadPtr + Item14Offset); + ((Chain*)(newHeadPtr + Item14Offset))->PNext = (Chain*) (newHeadPtr + Item15Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 16 items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item 15. @@ -10431,79 +12381,79 @@ public ManagedChain(out string errors, TChain chain) /// Do not forget to dispose the chain if you are no longer using it. /// public ManagedChain(ManagedChain previous, T15 item15 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - var item2Size = Marshal.SizeOf(); - var item3Size = Marshal.SizeOf(); - var item4Size = Marshal.SizeOf(); - var item5Size = Marshal.SizeOf(); - var item6Size = Marshal.SizeOf(); - var item7Size = Marshal.SizeOf(); - var item8Size = Marshal.SizeOf(); - var item9Size = Marshal.SizeOf(); - var item10Size = Marshal.SizeOf(); - var item11Size = Marshal.SizeOf(); - var item12Size = Marshal.SizeOf(); - var item13Size = Marshal.SizeOf(); - var item14Size = Marshal.SizeOf(); - var item15Size = Marshal.SizeOf(); - - var originalSize = headSize + item1Size + item2Size + item3Size + item4Size + item5Size + item6Size + item7Size + item8Size + item9Size + item10Size + item11Size + item12Size + item13Size + item14Size; - var newSize = originalSize + item15Size; - - _headPtr = Marshal.AllocHGlobal(newSize); + var previousSize = MemorySize - Item15Size; // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); - - _item1Ptr = _headPtr + headSize; - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; - - _item2Ptr = _item1Ptr + item1Size; - ((Chain*) _item1Ptr)->PNext = (Chain*) _item2Ptr; - - _item3Ptr = _item2Ptr + item2Size; - ((Chain*) _item2Ptr)->PNext = (Chain*) _item3Ptr; - - _item4Ptr = _item3Ptr + item3Size; - ((Chain*) _item3Ptr)->PNext = (Chain*) _item4Ptr; - - _item5Ptr = _item4Ptr + item4Size; - ((Chain*) _item4Ptr)->PNext = (Chain*) _item5Ptr; - - _item6Ptr = _item5Ptr + item5Size; - ((Chain*) _item5Ptr)->PNext = (Chain*) _item6Ptr; - - _item7Ptr = _item6Ptr + item6Size; - ((Chain*) _item6Ptr)->PNext = (Chain*) _item7Ptr; - - _item8Ptr = _item7Ptr + item7Size; - ((Chain*) _item7Ptr)->PNext = (Chain*) _item8Ptr; - - _item9Ptr = _item8Ptr + item8Size; - ((Chain*) _item8Ptr)->PNext = (Chain*) _item9Ptr; - - _item10Ptr = _item9Ptr + item9Size; - ((Chain*) _item9Ptr)->PNext = (Chain*) _item10Ptr; - - _item11Ptr = _item10Ptr + item10Size; - ((Chain*) _item10Ptr)->PNext = (Chain*) _item11Ptr; - - _item12Ptr = _item11Ptr + item11Size; - ((Chain*) _item11Ptr)->PNext = (Chain*) _item12Ptr; - - _item13Ptr = _item12Ptr + item12Size; - ((Chain*) _item12Ptr)->PNext = (Chain*) _item13Ptr; + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 15 + item15.StructureType(); + Marshal.StructureToPtr(item15, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); + ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); + ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); + ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); + ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); + ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); + ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); + ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); + ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); + ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); + ((Chain*)(_headPtr + Item11Offset))->PNext = (Chain*) (_headPtr + Item12Offset); + ((Chain*)(_headPtr + Item12Offset))->PNext = (Chain*) (_headPtr + Item13Offset); + ((Chain*)(_headPtr + Item13Offset))->PNext = (Chain*) (_headPtr + Item14Offset); + ((Chain*)(_headPtr + Item14Offset))->PNext = (Chain*) (_headPtr + Item15Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } + + /// + /// Creates a new with 15 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } - _item14Ptr = _item13Ptr + item13Size; - ((Chain*) _item13Ptr)->PNext = (Chain*) _item14Ptr; + /// + /// Creates a new with 15 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T15 item15) + { + item15 = Item15; - _item15Ptr = _item14Ptr + item14Size; - // Append the last structure - item15.StructureType(); - Marshal.StructureToPtr(item15, _item15Ptr, false); - ((Chain*) _item14Ptr)->PNext = (Chain*) _item15Ptr; + var newSize = MemorySize - Item15Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); + ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); + ((Chain*)(newHeadPtr + Item13Offset))->PNext = (Chain*) (newHeadPtr + Item14Offset); + ((Chain*)(newHeadPtr + Item14Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -10534,7 +12484,8 @@ public override IEnumerator GetEnumerator() public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, 2 => Item2, 3 => Item3, 4 => Item4, @@ -10594,41 +12545,28 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); - var item2Ptr = Interlocked.Exchange(ref _item2Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item2Ptr); - var item3Ptr = Interlocked.Exchange(ref _item3Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item3Ptr); - var item4Ptr = Interlocked.Exchange(ref _item4Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item4Ptr); - var item5Ptr = Interlocked.Exchange(ref _item5Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item5Ptr); - var item6Ptr = Interlocked.Exchange(ref _item6Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item6Ptr); - var item7Ptr = Interlocked.Exchange(ref _item7Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item7Ptr); - var item8Ptr = Interlocked.Exchange(ref _item8Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item8Ptr); - var item9Ptr = Interlocked.Exchange(ref _item9Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item9Ptr); - var item10Ptr = Interlocked.Exchange(ref _item10Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item10Ptr); - var item11Ptr = Interlocked.Exchange(ref _item11Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item11Ptr); - var item12Ptr = Interlocked.Exchange(ref _item12Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item12Ptr); - var item13Ptr = Interlocked.Exchange(ref _item13Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item13Ptr); - var item14Ptr = Interlocked.Exchange(ref _item14Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item14Ptr); - var item15Ptr = Interlocked.Exchange(ref _item15Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item15Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + Marshal.DestroyStructure(headPtr + Item8Offset); + Marshal.DestroyStructure(headPtr + Item9Offset); + Marshal.DestroyStructure(headPtr + Item10Offset); + Marshal.DestroyStructure(headPtr + Item11Offset); + Marshal.DestroyStructure(headPtr + Item12Offset); + Marshal.DestroyStructure(headPtr + Item13Offset); + Marshal.DestroyStructure(headPtr + Item14Offset); + Marshal.DestroyStructure(headPtr + Item15Offset); // Free memory block Marshal.FreeHGlobal(headPtr); diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt index c6355fa39e..42f5120923 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt @@ -1,10 +1,9 @@ <#@ template language="C#" #> <#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> <# var maximumItems = 16; - string parameterDocs(int index, string prefix) + string ParameterDocs(int index, string prefix) { var builder = new StringBuilder(prefix); builder.Append("The head of the chain."); @@ -22,7 +21,7 @@ return builder.ToString(); } - string parameterTypeDocs(int index, string prefix) + string ParameterTypeDocs(int index, string prefix) { var builder = new StringBuilder(prefix); builder.Append("The chain type"); @@ -40,7 +39,7 @@ return builder.ToString(); } - string typeList(int index) + string TypeList(int index) { var builder = new StringBuilder("TChain"); for (var i = 1; i < index; i++) @@ -52,7 +51,7 @@ return builder.ToString(); } - string paramList(int index) + string ParamList(int index) { var builder = new StringBuilder("TChain head = default"); for (var i = 1; i < index; i++) @@ -67,7 +66,7 @@ return builder.ToString(); } - string argList(int index) + string ArgList(int index) { var builder = new StringBuilder("head"); for (var i = 1; i < index; i++) @@ -79,7 +78,7 @@ return builder.ToString(); } - string constraintList(int index, string prefix) + string ConstraintList(int index, string prefix) { var builder = new StringBuilder(prefix); builder.Append("where TChain : struct, IChainStart"); @@ -95,6 +94,7 @@ return builder.ToString(); } #> +// ReSharper disable StaticMemberInGenericType using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -124,20 +124,20 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable public abstract void Dispose(); <# - for (var i = 2; i <= maximumItems; i++) + for (var i = 1; i <= maximumItems; i++) { - var tList = typeList(i); + var tList = TypeList(i); #> /// /// Creates a new with <#= i #> items. /// -<#= parameterDocs(i, " /// ") #> -<#= parameterTypeDocs(i, " /// ") #> +<#= ParameterDocs(i, " /// ") #> +<#= ParameterTypeDocs(i, " /// ") #> /// A new with <#= i #> items. - public static ManagedChain<<#= tList #>> Create<<#= tList #>>(<#= paramList(i) #>) -<#= constraintList(i, " ") #> + public static ManagedChain<<#= tList #>> Create<<#= tList #>>(<#= ParamList(i) #>) +<#= ConstraintList(i, " ") #> { - return new(<#= argList(i) #>); + return new(<#= ArgList(i) #>); } /// @@ -147,7 +147,7 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable /// The unmanaged chain to use as the basis of this chain. /// A new with <#= i #> items. public static ManagedChain<<#= tList #>> Load<<#= tList #>>(out string errors, TChain chain) -<#= constraintList(i, " ") #> +<#= ConstraintList(i, " ") #> { return new(out errors, chain); } @@ -159,29 +159,56 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable /// The unmanaged chain to use as the basis of this chain. /// A new with <#= i #> items. public static ManagedChain<<#= tList #>> Load<<#= tList #>>(TChain chain) -<#= constraintList(i, " ") #> +<#= ConstraintList(i, " ") #> { return new(out var _, chain); } <# - } // for (var 2 = 1; i <= maximumItems; i++) { + } // for (var i = 1; i <= maximumItems; i++) #> } <# - for (var i = 2; i <= maximumItems; i++) + for (var i = 1; i <= maximumItems; i++) { - var tList = typeList(i); + var tList = TypeList(i); #> /// /// A safely manages the pointers of a managed structure chain. /// -<#= parameterTypeDocs(i, "/// ") #> +<#= ParameterTypeDocs(i, "/// ") #> public unsafe class ManagedChain<<#= tList #>> : ManagedChain -<#= constraintList(i, " ") #> +<#= ConstraintList(i, " ") #> { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); +<# + for (var j = 1; j < i; j++) + { +#> + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item<#= j #>Offset = <#= j == 1 ? "HeadSize" : $"Item{j - 1}Offset + Item{j - 1}Size" #>; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item<#= j #>Size = Marshal.SizeOf>(); +<# + } // for (int j = 1; j < i; j++) { +#> + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = <#= i == 1 ? "HeadSize" : $"Item{i - 1}Offset + Item{i - 1}Size" #>; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -197,35 +224,35 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - <# for (var j = 1; j < i; j++) { #> - private IntPtr _item<#= j #>Ptr; /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item<#= j #>Ptr => (Chain*) _item<#= j #>Ptr; + public Chain* Item<#= j #>Ptr => (Chain*) (_headPtr + Item<#= j #>Offset); /// /// Gets or sets item #<#= j #> in the chain. /// public T<#= j #> Item<#= j #> { - get => Unsafe.AsRef>((Chain*) _item<#= j #>Ptr); + get => Unsafe.AsRef>(Item<#= j #>Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item<#= j #>Ptr)->PNext; - Marshal.StructureToPtr(value, _item<#= j #>Ptr, true); - ((Chain*) _item<#= j #>Ptr)->PNext = nextPtr; + var ptr = Item<#= j #>Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } <# @@ -233,45 +260,38 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain #> /// - /// Creates a new with <#= i #> items. + /// Creates a new with <#= i #> items from an existing memory block. /// -<#= parameterDocs(i, " /// ") #> - public ManagedChain(<#= paramList(i) #>) + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); -<# - for (var j = 1; j < i; j++) - { -#> - var item<#= j #>Size = Marshal.SizeOf>(); -<# - } // for (int j = 1; j < i; j++) { -#> + _headPtr = headPtr; + } - _headPtr = Marshal.AllocHGlobal(headSize<# - for (var j = 1; j < i; j++) - { -#> + item<#= j #>Size<# - } // for (int j = 1; j < i; j++) { -#>); + /// + /// Creates a new with <#= i #> items. + /// +<#= ParameterDocs(i, " /// ") #> + public ManagedChain(<#= ParamList(i) #>) + : this(Marshal.AllocHGlobal(MemorySize)) + { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); <# for (var j = 1; j < i; j++) { - var prevItem = j > 1 - ? $"item{j - 1}" - : "head"; #> - - _item<#= j #>Ptr = _<#= prevItem #>Ptr + <#= prevItem #>Size; + <#= j == 1 ? "Chain* " : "" #>itemPtr = Item<#= j #>Ptr; item<#= j #>.StructureType(); - Marshal.StructureToPtr(item<#= j #>, _item<#= j #>Ptr, false); - ((Chain*) _<#= prevItem #>Ptr)->PNext = (Chain*) _item<#= j #>Ptr; + Marshal.StructureToPtr(item<#= j #>, (nint)itemPtr, false); + <#= j == 1 ? "HeadPtr" : $"Item{j - 1}Ptr" #>->PNext = itemPtr; <# } // for (int j = 1; j < i; j++) { #> + <#= i == 1 ? "HeadPtr" : $"Item{i - 1}Ptr" #>->PNext = null; } /// @@ -280,139 +300,195 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; - StringBuilder errorBuilder = new StringBuilder(); - + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); <# - for (var j = 1; j < i; j++) + if (i == 1) { #> - currentPtr = currentPtr->PNext; + errors = string.Empty; +<# + } + else + { +#> + StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; +<# + for (var j = 1; j < i; j++) + { +#> + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item<#= j #>Offset); + newPtr = newPtr->PNext; + T<#= j #> item<#= j #> = default; - if (currentPtr is null) + <#= j == 1 ? "var " : "" #>expectedStructureType = item<#= j #>.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length <#= j #>, expected length <#= i #>"); - else { - expectedStructureType = item<#= j #>.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position <#= j + 1 #>; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item<#= j #> = Unsafe.AsRef>(currentPtr); + } else { <# - if (j == i -1) - { + if (j == i - 1) + { #> - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length <#= i #>"); + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length <#= i #>"); + existingPtr->PNext = null; + } <# - } // if (j == i -1) + } // if (j == i -1) #> + item<#= j #> = Unsafe.AsRef>(existingPtr); + } } - var item<#= j #>Size = Marshal.SizeOf>(); - + Marshal.StructureToPtr(item<#= j #>, (nint) newPtr, false); <# - } // for (int j = 1; j < i; j++) { + } // for (int j = 1; j < i; j++) { #> // Create string of errors errors = errorBuilder.ToString().Trim(); +<# + } // if (i == 1) {} else {... +#> + } - _headPtr = Marshal.AllocHGlobal(headSize<# - for (var j = 1; j < i; j++) + /// + /// Creates a new with <#= i #> by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain<<#= tList #>> Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); +<# + if (i > 1) { -#> + item<#= j #>Size<# - } // for (int j = 1; j < i; j++) { -#>); - Marshal.StructureToPtr(head, _headPtr, false); +#> + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); <# - for (var j = 1; j < i; j++) + } // if (i > 1) +#> +<# + for (var j = 2; j < i; j++) { - var prevItem = j > 1 - ? $"item{j - 1}" - : "head"; #> - - _item<#= j #>Ptr = _<#= prevItem #>Ptr + <#= prevItem #>Size; - Marshal.StructureToPtr(item<#= j #>, _item<#= j #>Ptr, false); - ((Chain*) _<#= prevItem #>Ptr)->PNext = (Chain*) _item<#= j #>Ptr; + ((Chain*)(newHeadPtr + Item<#= j - 1 #>Offset))->PNext = (Chain*) (newHeadPtr + Item<#= j #>Offset); <# } // for (int j = 1; j < i; j++) { #> + return new ManagedChain<<#= tList #>>(newHeadPtr); } <# - if (i > 2) + if (i > 1) { + var shortTList = TypeList(i - 1); #> /// - /// Creates a new with <#= i #> items. + /// Creates a new with <#= i #> items, by appending + /// to the end of this chain. /// /// The chain to append to. /// Item <#= i - 1 #>. /// /// Do not forget to dispose the chain if you are no longer using it. /// - public ManagedChain(ManagedChain<<#= typeList(i - 1) #>> previous, T<#= i - 1 #> item<#= i - 1 #> = default) + public ManagedChain(ManagedChain<<#= shortTList #>> previous, T<#= i - 1 #> item<#= i - 1 #> = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); + var previousSize = MemorySize - Item<#= i - 1 #>Size; + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item <#= i - 1 #> + item<#= i - 1 #>.StructureType(); + Marshal.StructureToPtr(item<#= i - 1 #>, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); <# - for (var j = 1; j < i; j++) + for (var j = 2; j < i; j++) { #> - var item<#= j #>Size = Marshal.SizeOf>(); + ((Chain*)(_headPtr + Item<#= j - 1 #>Offset))->PNext = (Chain*) (_headPtr + Item<#= j #>Offset); <# } // for (int j = 1; j < i; j++) { #> + ((Chain*)(_headPtr + previousSize))->PNext = null; + } - var originalSize = headSize<# - for (var j = 1; j < i - 1; j++) - { -#> + item<#= j #>Size<# - } // for (int j = 1; j < i; j++) { -#>; - var newSize = originalSize + item<#= i - 1 #>Size; + /// + /// Creates a new with <#= i - 1 #> items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain<<#= shortTList #>> Truncate() + { + return Truncate(out var _); + } + + /// + /// Creates a new with <#= i - 1 #> items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain<<#= shortTList #>> Truncate(out T<#= i - 1 #> item<#= i - 1 #>) + { + item<#= i - 1 #> = Item<#= i - 1 #>; - _headPtr = Marshal.AllocHGlobal(newSize); + var newSize = MemorySize - Item<#= i - 1 #>Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, originalSize, originalSize); + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers <# - for (var j = 1; j < i; j++) + if (i > 2) { - var prevItem = j > 1 - ? $"item{j - 1}" - : "head"; #> - - _item<#= j #>Ptr = _<#= prevItem #>Ptr + <#= prevItem #>Size; + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); <# - if (j == i - 1) + for (var j = 2; j < i; j++) { #> - // Append the last structure - item<#= j #>.StructureType(); - Marshal.StructureToPtr(item<#= j #>, _item<#= j #>Ptr, false); + ((Chain*)(newHeadPtr + Item<#= j - 1 #>Offset))->PNext = <#= j == i -1 ? "null" : $"(Chain*) (newHeadPtr + Item{j}Offset)"#>; <# - } // if (j == i - 1) -#> - ((Chain*) _<#= prevItem #>Ptr)->PNext = (Chain*) _item<#= j #>Ptr; + } // for (int j = 1; j < i - 1; j++) + } + else // if (i > 1) + { + #> + ((Chain*)newHeadPtr)->PNext = null; <# - } // for (int j = 1; j < i; j++) { + } #> + return new ManagedChain<<#= shortTList #>>(newHeadPtr); } <# - } //if (i > 2) + } // if (i > 1) if (i < maximumItems) { + var bigTList = TypeList(i + 1); #> /// @@ -422,9 +498,9 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain /// Item <#= i #>. /// Type of Item <#= i #> /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain<<#= tList #>, T<#= i #>> Append>(T<#= i #> item<#= i #> = default) + public ManagedChain<<#= bigTList #>> Append>(T<#= i #> item<#= i #> = default) where T<#= i #>: struct, IExtendsChain { return new ManagedChain<<#= tList #>, T<#= i #>>(this, item<#= i #>); @@ -454,13 +530,14 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain public override IChainable this[int index] => index switch { - 0 => Head,<# - for (var j = 1; j < i; j++) - { + 0 => Head, +<# + for (var j = 1; j < i; j++) + { #> <#= j #> => Item<#= j #>, <# - } // for (int j = 1; j < i; j++) { + } // for (int j = 1; j < i; j++) { #> _ => throw new IndexOutOfRangeException() }; @@ -468,30 +545,32 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain /// /// Deconstructs this chain. /// -<#= parameterDocs(i, " /// ") #> +<#= ParameterDocs(i, " /// ") #> public void Deconstruct(out TChain head<# - for (var j = 1; j < i; j++) - { + for (var j = 1; j < i; j++) + { #>, out T<#= j #> item<#= j #><# - } // for (int j = 1; j < i; j++) { + } // for (int j = 1; j < i; j++) { #>) { head = Head; <# - for (var j = 1; j < i; j++) - { + for (var j = 1; j < i; j++) + { #> item<#= j #> = Item<#= j #>; <# - } // for (int j = 1; j < i; j++) { + } // for (int j = 1; j < i; j++) { #> } /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); @@ -499,8 +578,7 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain for (var j = 1; j < i; j++) { #> - var item<#= j #>Ptr = Interlocked.Exchange(ref _item<#= j #>Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item<#= j #>Ptr); + Marshal.DestroyStructure>(headPtr + Item<#= j #>Offset); <# } // for (int j = 1; j < i; j++) { #> @@ -510,5 +588,5 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain } } <# - } // for (var i = 2; i <= maximumItems; i++) { + } // for (var i = 1; i <= maximumItems; i++) #> \ No newline at end of file diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs index 9a2fa6ecf8..bd7fdeb97e 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs @@ -39,5 +39,12 @@ StructureType IStructuredType.StructureType() return SType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr; } + /// + unsafe Chain* IChainable.PNext + { + get => (Chain*) PNext; + set => PNext = value; + } + #endregion } \ No newline at end of file diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs index 5f30fcd144..9e9bf8ac5d 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs @@ -39,5 +39,12 @@ StructureType IStructuredType.StructureType() return SType = StructureType.PhysicalDeviceDescriptorIndexingFeaturesExt; } + /// + unsafe Chain* IChainable.PNext + { + get => (Chain*) PNext; + set => PNext = value; + } + #endregion } \ No newline at end of file diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs index f9aae21d47..9b12590611 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs @@ -43,5 +43,12 @@ StructureType IStructuredType.StructureType() return SType = StructureType.PhysicalDeviceFeatures2; } + /// + unsafe Chain* IChainable.PNext + { + get => (Chain*) PNext; + set => PNext = value; + } + #endregion } \ No newline at end of file From d1ced738e8179afcadcccf4346cd522a310b950c Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sun, 7 Nov 2021 21:57:43 +0000 Subject: [PATCH 27/34] docs: Updated Chaining proposals to match new functionality. Also cleaned up some tests. --- ...Struct Chaining - #2 Unmanaged Chaining.md | 34 +-- ...n Struct Chaining - #3 Managed Chaining.md | 241 +++++++++++++----- .../TestChains.cs | 14 +- .../TestCompilation.cs | 4 +- .../TestManagedChains.cs | 30 +-- .../PrototypeStructChaining.csproj | 15 +- 6 files changed, 228 insertions(+), 110 deletions(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md index b627be5c9a..513cd4487d 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md @@ -18,7 +18,8 @@ The `IChainable` interface extends the `IStructuredType` interface from [Proposal - Vulkan Struct Chaining - #1 StructureType correction](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md) and so the explicit implementation of `IChainable.StructureType()` from [that proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md#istructuretype-implementation) -is triggerred for the structure, providing a mechanism for ensuring the `SType` is correctly set. +is triggerred for the structure, providing a mechanism for ensuring the `SType` is correctly set. It then exposes +a `Chain* PNext { get; set; }` property for easy access to the next item in the chain. The presence of the `IChainable` interface, also acts as a **guarantee** that it is safe to cast any pointer of a struct implementing it to a pointer to a `Chain` struct, which is a struct which has just the `SType` and `PNext` fields @@ -31,16 +32,15 @@ run time. offset 0, i.e. in the first position. However, rather than extending `IChainable` directly, it will be more common to choose one of `IChainStart` -or `IExtendsChain` (both of which extend `IChainable`). It does this based on the `structextends` attribute -provided in +or `IExtendsChain` (both of which extend `IChainable`). `BuildTools` will do this based on the `structextends` +attribute provided in the [Vulkan Specification](https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/registry/vk.xml)). -For example, if `struct B` extends `struct A` (as per -the [Vulkan Specification](https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/registry/vk.xml)), then -`struct B` will be marked with `IExtendsChain` and `struct A` will be marked with `IChainStart`. A struct may only -extend `IChainStart` once (even though it may appear in the `structextends` attribute of many structs), but is may -implement multiple `IExtendsChain` interfaces. It is also feasible for a struct to implement both (i.e. be able -to extend other chains, as well as being a chain start), a real example of this can be seen +For example, if `struct B` extends `struct A`, then `struct B` will be marked with `IExtendsChain` and `struct A` +will be marked with `IChainStart`. A struct may only extend `IChainStart` once (even though it may appear in +the `structextends` attribute of many structs), but is may implement multiple `IExtendsChain` interfaces. It is +also feasible for a struct to implement both (i.e. be able to extend other chains, as well as being a chain start), a +real example of this can be seen [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs). As a result, `IChainable` will not usually be directly implemented (just as it is unlikely to see `IStructuredType` @@ -52,12 +52,12 @@ will be explicitly marked as `IChainable`. Whenever a struct is marked as `IChainStart` a static `ref [StructType] Chain(out [StructType]) capture);` method is also added, providing an easy form of starting a chain with default values. As `IChainStart` also -implements `IStructuredType` (via `IChainable`), then a chain start will have two additional methods generated (the -static -`Chain(out)` method and the explicit `IStructuredType.StructureType()` implementation); as compared to all other -`IChainable` structs, which will only have the explicit `IStructuredType.StructureType()` implementation from +implements `IChainable`, which implements `IStructuredType`, then a chain start will have three additional methods +generated (the static `Chain(out)` method and the explicit `IStructuredType.StructureType()` and `IChainable.PNext` +implementation); as compared to all other `IChainable` structs, which will only have the +explicit `IStructuredType.StructureType()` implementation from [Proposal - Vulkan Struct Chaining - #1 StructureType correction](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md) -. +and the explicit `Chain* IChainable.PNext { get; set;}` property from this proposal. The remaining functionality is provided entirely by the following new extension methods: @@ -115,13 +115,13 @@ What this proposal does not do (some of these _are_ addressed in [Proposal - Vulkan Struct Chaining - #3 Managed Chaining](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%233%20Managed%20Chaining.md)) is manage pointers of structures that find themselves on the heap. Any supplied structures should be held on the stack, once moved to the heap their `PNext` values can no longer be trusted as the GC is free to move structures in heap -memory. The interface of this proposal makes it difficult to use with heap objects, but it is not impossible. The +memory. The proposed extension methods make it difficult to use with heap objects, but it is not impossible. The presence of the `ManagedChain` classes from [the proposal for managed chains](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%233%20Managed%20Chaining.md), along with a well documented API should highlight the danger of such practices. -Indeed, it is important to remember that such dangers are already part of the existing implementation are a feature of -using unmanaged pointers in .NET rather than a 'limitation' of this proposal. +Indeed, it is important to remember that such dangers are already part of the existing implementation and are a feature of +using unmanaged pointers in .NET rather than a limitation of this proposal. # Usage diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md index 8ffb1cb6e5..47c6bbfc89 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md @@ -17,7 +17,7 @@ performance. However, many consumers are uncomfortable with pointers, and are especially prone to introducing bugs when placing structs onto the heap. This proposal provides a convenient `ManagedChain` class, and multiple -descendent `ManagedChain` classes to safely fix the structures in memory and prevent pointer bugs. +descendent `ManagedChain` classes to safely fix the structures in memory and prevent pointer bugs. Whenever a structure is loaded into the `ManagedChain` its `SType` and `PNext` are forced to be correct, preventing errors. Structures can be replaced at any time, and will be inserted efficiently into the chain as an O(1) operation. @@ -36,34 +36,32 @@ errors. Structures can be replaced at any time, and will be inserted efficiently # Design Decisions - There are no requirements to extend `BuildTools`, or add any additional information to the `IChainable` structures. -- Although the `ManagedChain` generic classes are auto-generated (for convenience) this is done using T4 +- Although the `ManagedChain` generic classes are auto-generated (for convenience) this is done using T4 templating, an implementation of which is provided [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt). - For improved performance, the chain's structures are held in a single block of contiguous unmanaged memory, as the memory is unmanaged, the position of the structures remains fixed, even though the containing object can be safely - moved around by the GC in the heap. + moved around by the GC in the heap. Indeed a pointer to this block is the only data stored by an instance of any + `ManageChain` object, despite all the functionality provided! - The structure accessors return a copy of the structures, and always correct the `SType` and `PNext` on input. Even though the `PNext` values are exposed there is no way to modify them from outside the class, guaranteeing their safety. Open questions: -- Should we expose 8, 16 or 32 `ManagedChain` classes? +- Should we expose 8, 16 or 32 `ManagedChain` classes? - Do we want to stick with `TChain chain, T1 item1`, or use `T1 item1, T2 item2` ala `Tuple`? - Although the constructors used by `ManagedChain.Create` and `ManagedChain.Load` could be made `internal`, I don't propose we do so. Primarily, the main benefit of the static methods is type inference, but, as chain building is frequently done with defaults then direct constructor access does not have a disadvantage, and can take advantage of implicit typing when assigning to an already typed field/property. Having both forms available is therefore convenient. -- Currently `ManagedChain` is the smallest chain, there is a strong case to be made for - a `ManagedChain`. - The current `Load` methods expect an unmanaged chain that matches the supplied type constraints, and is of the same length. This is useful, as coders will normally expect a particular chain. We could additionally add more lax `Import` methods that will import an unmanaged chain into a managed chain by populating any positions with structure types found in the unmanaged chain, no matter at what position they are found. This is not entirely unreasonable as the order of chains (after the start) is not fixed in Vulkan, and it will allow importing existing chains where the order doesn't matter. -- Similar to `Append` do we want a `Truncate` method to trim the end of a chain? - Similar to `Append` and `Truncate` we could also add `Insert` and `Remove` methods, though slightly more complex, as we'd have to generate multiples of each, it is not difficult to do, for example: @@ -173,8 +171,8 @@ ensures the `PNext` value pointing to it is maintained. ### Appending to a chain -You can call `Append` on a `ManagedChain` to efficiently create a new, larger, `ManagedChain` with a new item appended -to the end, e.g: +You can call `Append` on a `ManagedChain` (of length < 16) to efficiently create a new, larger, `ManagedChain` with a +new item appended to the end, e.g: ```csharp using var chain = new ManagedChain( @@ -192,10 +190,33 @@ Assert.True(newChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); finished with, when using the `Append` method you will produce a new `ManagedChain` and should not forget to dispose the original if it is no longer needed. +### Truncate + +Similarly, you can `Truncate` a chain (of length > 1) to get an instance of a smaller chain: +```csharp +using var chain = ManagedChain.Create(); +using var chain2 = chain.Append(); +// Remove the indexing features we just added (note the out parameter is optional) +using var chain3 = chain2.Truncate(out var indexingFeatures); + +Assert.Equal(1, chain.Count); +Assert.Equal(2, chain2.Count); +Assert.Equal(1, chain3.Count); +``` + +### Duplicate + +You can efficiently duplicate a managed chain by calling Duplicate on it: +```csharp +using var chain = new ManagedChain(); +using var copy = chain.Duplicate(); +``` + ### Loading from an unmanaged chain If you have created an unmanaged chain and would like to load that into a `ManagedChain` you can use one of the -`ManagedChain.Load` methods: +`ManagedChain.Load` methods: ```csharp // Load an unmanaged chain @@ -265,7 +286,7 @@ equivalent constructor to `Load(TChain)` as that would be ambiguous. ### IReadOnlyList -All the fully generic `ManageChain` types extend `ManagedChain` which implements `IDisposable` +All the fully generic `ManageChain` types extend `ManagedChain` which implements `IDisposable` and `IReadOnlyList`. The latter allowing for easy consumption of any `ManagedChain`, e.g.: ```csharp @@ -292,7 +313,7 @@ Assert.IsType(structures[2]); ### Deconstruction -Each `ManageChain` has a corresponding deconstructor for convenience, e.g.: +Each `ManageChain` has a corresponding deconstructor for convenience, e.g.: ```csharp using var chain = new ManagedChain, IDisposable A class is generated for each valid size of a chain, here is one example: ```csharp + /// /// A safely manages the pointers of a managed structure chain. /// @@ -385,7 +407,27 @@ public unsafe class ManagedChain : ManagedChain where TChain : struct, IChainStart where T1 : struct, IExtendsChain { - private IntPtr _headPtr; + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item1Offset + Item1Size; + + private nint _headPtr; /// /// Gets a pointer to the current head. @@ -401,53 +443,61 @@ public unsafe class ManagedChain : ManagedChain set { value.StructureType(); - var nextPtr = ((Chain*) _headPtr)->PNext; + var ptr = (Chain*) _headPtr; + var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); - ((Chain*) _headPtr)->PNext = nextPtr; + ptr->PNext = nextPtr; } } - private IntPtr _item1Ptr; - /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) _item1Ptr; + public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. /// public T1 Item1 { - get => Unsafe.AsRef((Chain*) _item1Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var nextPtr = ((Chain*) _item1Ptr)->PNext; - Marshal.StructureToPtr(value, _item1Ptr, true); - ((Chain*) _item1Ptr)->PNext = nextPtr; + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } } + /// + /// Creates a new with 2 items from an existing memory block. + /// + /// The pointer to the head of the chain.. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + /// /// Creates a new with 2 items. /// /// The head of the chain. /// Item 1. public ManagedChain(TChain head = default, T1 item1 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Calculate memory requirements - var headSize = Marshal.SizeOf(); - var item1Size = Marshal.SizeOf(); - - _headPtr = Marshal.AllocHGlobal(headSize + item1Size); head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - - _item1Ptr = _headPtr + headSize; + Chain* itemPtr = Item1Ptr; item1.StructureType(); - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + Item1Ptr->PNext = null; } /// @@ -456,43 +506,114 @@ public unsafe class ManagedChain : ManagedChain /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. public ManagedChain(out string errors, TChain chain) + : this(Marshal.AllocHGlobal(MemorySize)) { - // Load existing chain first, so any errors occur before we allocate memory - var head = chain; - var headSize = Marshal.SizeOf(); - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - StructureType expectedStructureType; + chain.StructureType(); + Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); + var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); + var newPtr = (Chain*) _headPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (Chain*) (_headPtr + Item1Offset); + newPtr = newPtr->PNext; - currentPtr = currentPtr->PNext; T1 item1 = default; - if (currentPtr is null) + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); - else { - expectedStructureType = item1.StructureType(); - if (currentPtr->SType != expectedStructureType) { + } else { + if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(currentPtr->SType) + .Append(existingPtr->SType) .Append(" at position 2; expected ") .Append(expectedStructureType) .AppendLine(); - } else - item1 = Unsafe.AsRef(currentPtr); - if (currentPtr->PNext is not null) - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); + existingPtr->PNext = null; + } + item1 = Unsafe.AsRef(existingPtr); + } } - var item1Size = Marshal.SizeOf(); - + Marshal.StructureToPtr(item1, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + } - _headPtr = Marshal.AllocHGlobal(headSize + item1Size); - Marshal.StructureToPtr(head, _headPtr, false); + /// + /// Creates a new with 2 by copying this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Duplicate() + { + var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + return new ManagedChain(newHeadPtr); + } - _item1Ptr = _headPtr + headSize; - Marshal.StructureToPtr(item1, _item1Ptr, false); - ((Chain*) _headPtr)->PNext = (Chain*) _item1Ptr; + /// + /// Creates a new with 2 items, by appending + /// to the end of this chain. + /// + /// The chain to append to. + /// Item 1. + /// + /// Do not forget to dispose the chain if you are no longer using it. + /// + public ManagedChain(ManagedChain previous, T1 item1 = default) + : this(Marshal.AllocHGlobal(MemorySize)) + { + var previousSize = MemorySize - Item1Size; + // Block copy original struct data for speed + Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + + // Append item 1 + item1.StructureType(); + Marshal.StructureToPtr(item1, _headPtr + previousSize, false); + + // Update all pointers + ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((Chain*)(_headPtr + previousSize))->PNext = null; + } + + /// + /// Creates a new with 1 items, by removing the last item + /// from this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate() + { + return Truncate(out var _); + } + + /// + /// Creates a new with 1 items, by removing + /// from the end of this chain. + /// + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + public ManagedChain Truncate(out T1 item1) + { + item1 = Item1; + + var newSize = MemorySize - Item1Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((Chain*)newHeadPtr)->PNext = null; + return new ManagedChain(newHeadPtr); } /// @@ -502,7 +623,7 @@ public unsafe class ManagedChain : ManagedChain /// Item 2. /// Type of Item 2 /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// public ManagedChain Append(T2 item2 = default) where T2: struct, IExtendsChain @@ -524,7 +645,8 @@ public unsafe class ManagedChain : ManagedChain public override IChainable this[int index] => index switch { - 0 => Head, 1 => Item1, + 0 => Head, + 1 => Item1, _ => throw new IndexOutOfRangeException() }; @@ -542,13 +664,14 @@ public unsafe class ManagedChain : ManagedChain /// public override void Dispose() { - var headPtr = Interlocked.Exchange(ref _headPtr, IntPtr.Zero); - if (headPtr == IntPtr.Zero) return; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } // Destroy all structures Marshal.DestroyStructure(headPtr); - var item1Ptr = Interlocked.Exchange(ref _item1Ptr, IntPtr.Zero); - Marshal.DestroyStructure(item1Ptr); + Marshal.DestroyStructure(headPtr + Item1Offset); // Free memory block Marshal.FreeHGlobal(headPtr); diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs index 0debaa5543..2ccadfa81b 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs @@ -19,7 +19,7 @@ public unsafe void TestAddNext() // Ensure all pointers set correctly Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); Assert.Equal((nint) (&accelerationStructureFeaturesKhr), (nint) indexingFeatures.PNext); - Assert.Equal((nint) 0, (nint) accelerationStructureFeaturesKhr.PNext); + Assert.Equal(0, (nint) accelerationStructureFeaturesKhr.PNext); // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); @@ -76,7 +76,7 @@ public unsafe void TestSetNext() Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); Assert.Equal((nint) (&accelerationStructureFeaturesKhr), (nint) indexingFeatures.PNext); - Assert.Equal((nint) 0, (nint) accelerationStructureFeaturesKhr.PNext); + Assert.Equal(0, (nint) accelerationStructureFeaturesKhr.PNext); Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); @@ -104,7 +104,7 @@ public unsafe void TestSetNextUpdates() .SetNext(ref indexingFeatures); Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); - Assert.Equal((nint) 0, (nint) indexingFeatures.PNext); + Assert.Equal(0, (nint) indexingFeatures.PNext); Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); @@ -117,7 +117,7 @@ public unsafe void TestSetNextUpdates() features2.SetNext(ref indexingFeatures2); Assert.Equal((nint) (&indexingFeatures2), (nint) features2.PNext); - Assert.Equal((nint) 0, (nint) indexingFeatures2.PNext); + Assert.Equal(0, (nint) indexingFeatures2.PNext); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures2.SType); @@ -139,7 +139,7 @@ public unsafe void TestSetNextAlwaysAdd() .SetNext(ref indexingFeatures); Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); - Assert.Equal((nint) 0, (nint) indexingFeatures.PNext); + Assert.Equal(0, (nint) indexingFeatures.PNext); Assert.Equal(StructureType.PhysicalDeviceFeatures2, features2.SType); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); @@ -153,7 +153,7 @@ public unsafe void TestSetNextAlwaysAdd() Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); Assert.Equal((nint) (&indexingFeatures2), (nint) indexingFeatures.PNext); - Assert.Equal((nint) 0, (nint) indexingFeatures2.PNext); + Assert.Equal(0, (nint) indexingFeatures2.PNext); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures2.SType); @@ -172,7 +172,7 @@ public unsafe void TestWithoutChain() // However, note that AddNext will still coerce the SType of createInfo. createInfo.AddNext(out PhysicalDeviceFeatures2 features2); Assert.Equal((nint) (&features2), (nint) createInfo.PNext); - Assert.Equal((nint) 0, (nint) features2.PNext); + Assert.Equal(0, (nint) features2.PNext); // Note, even though we didn't use chain, we have still coerced the SType Assert.Equal(StructureType.DeviceCreateInfo, createInfo.SType); diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs index 0d4c192599..e8e9163d03 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs @@ -64,7 +64,7 @@ private IReadOnlyList CheckCompile(string code) } [Fact] - public unsafe void TestCantAddUnsupportedNext() + public void TestCantAddUnsupportedNext() { var diagnostics = CheckCompile ( @@ -80,7 +80,7 @@ public unsafe void TestCantAddUnsupportedNext() } [Fact] - public unsafe void TestCanAddSupportedNext() + public void TestCanAddSupportedNext() { var diagnostics = CheckCompile ( diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs index 6f212a3d1b..268447d33f 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs @@ -21,7 +21,7 @@ public unsafe void TestManagedChain() // Ensure pointers set correctly Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); - Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + Assert.Equal(0, (nint) chain.Item2.PNext); } [Fact] @@ -38,7 +38,7 @@ public unsafe void TestManagedChainReplaceHead() // Ensure pointers set correctly Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); - Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + Assert.Equal(0, (nint) chain.Item2.PNext); Assert.Equal(0U, chain.Head.Flags); @@ -81,7 +81,7 @@ public unsafe void TestManagedChainReplaceMiddle() // Ensure pointers set correctly Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); - Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + Assert.Equal(0, (nint) chain.Item2.PNext); // Check our value was set Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); @@ -101,7 +101,7 @@ public unsafe void TestManagedChainReplaceMiddle() // Note all the pointers are still correct (and have not changed) Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); - Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + Assert.Equal(0, (nint) chain.Item2.PNext); // As is the SType Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); @@ -121,7 +121,7 @@ public unsafe void TestManagedChainDuplicate() // Ensure pointers set correctly Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); - Assert.Equal((nint) 0, (nint) chain.Item1.PNext); + Assert.Equal(0, (nint) chain.Item1.PNext); // Check flag set Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); @@ -134,7 +134,7 @@ public unsafe void TestManagedChainDuplicate() // Ensure pointers set correctly Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); - Assert.Equal((nint) 0, (nint) chain.Item1.PNext); + Assert.Equal(0, (nint) chain.Item1.PNext); // Check flag set Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); @@ -158,7 +158,7 @@ public unsafe void TestManagedChainAppend() // Ensure pointers set correctly Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); - Assert.Equal((nint) 0, (nint) chain.Item1.PNext); + Assert.Equal(0, (nint) chain.Item1.PNext); // Check flag set Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); @@ -173,7 +173,7 @@ public unsafe void TestManagedChainAppend() // Ensure pointers set correctly Assert.Equal((nint) newChain.Item1Ptr, (nint) newChain.Head.PNext); Assert.Equal((nint) newChain.Item2Ptr, (nint) newChain.Item1.PNext); - Assert.Equal((nint) 0, (nint) newChain.Item2.PNext); + Assert.Equal(0, (nint) newChain.Item2.PNext); // Check flag still set Assert.True(newChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); @@ -204,7 +204,7 @@ public unsafe void TestManagedChainTruncate() // Ensure pointers set correctly Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); - Assert.Equal((nint) 0, (nint) chain.Item2.PNext); + Assert.Equal(0, (nint) chain.Item2.PNext); // Check flag set Assert.True(chain.Item2.AccelerationStructure); @@ -219,7 +219,7 @@ public unsafe void TestManagedChainTruncate() // Ensure pointers set correctly Assert.Equal((nint) newChain.Item1Ptr, (nint) newChain.Head.PNext); - Assert.Equal((nint) 0, (nint) newChain.Item1.PNext); + Assert.Equal(0, (nint) newChain.Item1.PNext); // Check removed type flag Assert.True(accelerationStructure.AccelerationStructure); @@ -261,11 +261,11 @@ public unsafe void TestManagedChainLoad() // Ensure pointers set correctly Assert.Equal((nint) managedChain.Item1Ptr, (nint) managedChain.Head.PNext); Assert.Equal((nint) managedChain.Item2Ptr, (nint) managedChain.Item1.PNext); - Assert.Equal((nint) 0, (nint) managedChain.Item2.PNext); + Assert.Equal(0, (nint) managedChain.Item2.PNext); } [Fact] - public unsafe void TestManagedChainLoadWithError() + public void TestManagedChainLoadWithError() { var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures { @@ -301,7 +301,7 @@ public unsafe void TestManagedChainLoadWithError() } [Fact] - public unsafe void TestManagedChainLoadWithErrorTooLong() + public void TestManagedChainLoadWithErrorTooLong() { var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures { @@ -329,7 +329,7 @@ public unsafe void TestManagedChainLoadWithErrorTooLong() } [Fact] - public unsafe void TestReadOnlyList() + public void TestReadOnlyList() { using var chain = new ManagedChain(); @@ -353,7 +353,7 @@ public unsafe void TestReadOnlyList() } [Fact] - public unsafe void TestDeconstructor() + public void TestDeconstructor() { using var chain = new ManagedChain(); diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj index 643b5beaf5..79d8733662 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -27,16 +27,11 @@ - - True - True - ManagedChain.gen.tt - - - True - True - ManagedChain.gen.tt - + + True + True + ManagedChain.gen.tt + From e07f72fa891333a8999b4d35583fd4b6df267428 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sun, 7 Nov 2021 23:37:33 +0000 Subject: [PATCH 28/34] feat: Added chain metadata extensions. * Added the `Extensions`, `Extenders`, `ClrTypes` and `StructureTypes` dictionaries to `Chain`. * Added the `ClrType`, `StructureType`, `IsChainStart`, `IsChainable`, `CanExtend` and `CanBeExtendedBy` extension methods to `ChainExtensions`. * Finished Proposal #4 on Chaining Metadata extension. --- ...ining - #4 Chaining Metadata extensions.md | 382 +++++++++++++++++- .../PrototypeStructChaining.Test.csproj | 10 +- .../TestChainMetadata.cs | 58 +++ .../TestChains.cs | 4 +- .../TestManagedChains.cs | 28 +- .../PrototypeStructChaining/Chain.cs | 64 +++ .../ChainExtensions.cs | 129 +++++- ...DeviceAccelerationStructureFeaturesKhr.cs} | 4 +- 8 files changed, 651 insertions(+), 28 deletions(-) create mode 100644 src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainMetadata.cs rename src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/{PhysicalDeviceAccelerationStructureFeaturesKHR.cs => PhysicalDeviceAccelerationStructureFeaturesKhr.cs} (90%) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md index 6039b01fcd..bd2ed5db6c 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md @@ -1,17 +1,393 @@ # Summary -TODO + +**_This proposal is dependent +on [Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) +._** + +Having extended `BuildTools` to make use of the `structextends` attribute, as part of +the [unmanaged chaining proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) +it is possible to supply that metadata in a ready form for use by consumers of the library, without them needing to +resort to reflection. + +There are a number of potential use cases, most specifically validating that a supply `IChainable` structure is valid +for a given chain, at runtime. To facilitate the most common scenario 4 extension methods are also added. # Contributors + - [Craig Dean, DevDecoder](https://github.com/thargy) # Current Status + - [x] Proposed - [ ] Discussed with API Review Board (ARB) - [ ] Approved - [ ] Implemented # Design Decisions -TODO + +- It is possible to get the same information presented statically by this proposal by creative use of reflection, + however, it is non-trivial and costly to do so. +- When combined with the + [Proposal - Vulkan Struct Chaining - #3 Managed Chaining](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%233%20Managed%20Chaining.md) + the above functionality makes handling of non-generic chains at runtime significantly easier, which is great for + library writers. +- Though 4 collections are proposed, they are grouped in pairs, providing two-way mapping. It is possible to only + provide one of each pair, and leave the reversal to the consumer, though that would make the extension methods + impractical. +- As .Net Standard 2.0 does not support `IReadOnlySet` we make use of the `IReadOnlyCollection` interface. # Proposed API -TODO \ No newline at end of file + +## Auto-generated Metadata Structures + +The `Extensions` dictionary is added to the `Chain` structure from +the [unmanaged chaining proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) +for discoverability. It is a direct mapping of the `structextends` attribute, and is therefore trivial to generate. +Below is a cut down example to illustrate what will be generated: + +```csharp +public struct Chain : IChainable +{ + ... + /// + /// Provides a set of all the s that can be extended by a . + /// + public static readonly IReadOnlyDictionary> Extensions = + new Dictionary> + { + [StructureType.PhysicalDeviceFeatures2] = new HashSet + { + StructureType.DeviceCreateInfo + }, + [StructureType.PhysicalDeviceDescriptorIndexingFeatures] = new HashSet + { + StructureType.PhysicalDeviceFeatures2, + StructureType.DeviceCreateInfo + }, + [StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr] = new HashSet + { + StructureType.PhysicalDeviceFeatures2, + StructureType.DeviceCreateInfo + }, + ... + }; +} +``` + +## Extenders (Optional) + +By contrast the `Extenders` dictionary, it the reverse mapping of the `Extensions` dictionary, providing quick reverse +lookup. As this is slightly more complex to generate, it could be left to the consumer (who can generate it easily +from `Extensions` when needed). + +```csharp +public struct Chain : IChainable +{ + ... + /// + /// Provides a set of all the s that can extend a . + /// + public static readonly IReadOnlyDictionary> Extenders = + new Dictionary> + { + [StructureType.DeviceCreateInfo] = new HashSet + { + StructureType.PhysicalDeviceFeatures2, StructureType.PhysicalDeviceDescriptorIndexingFeatures, + StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr + }, + [StructureType.PhysicalDeviceFeatures2] = new HashSet + { + StructureType.PhysicalDeviceDescriptorIndexingFeatures, + StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr + }, + ... + }; +} +``` + +### ClrTypes + +The `ClrTypes` dictionary provides a `ClrType` for each `StructureType`, it is trivial to generate with existing +information: + +```csharp +public struct Chain : IChainable +{ + ... + /// + /// Provides a mapping from the to the corresponding . + /// + public static readonly IReadOnlyDictionary ClrTypes = + new Dictionary + { + [StructureType.DeviceCreateInfo] = typeof(DeviceCreateInfo), + [StructureType.PhysicalDeviceFeatures2] = typeof(PhysicalDeviceFeatures2), + [StructureType.PhysicalDeviceDescriptorIndexingFeatures]= typeof(PhysicalDeviceDescriptorIndexingFeatures), + [StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr] = typeof(PhysicalDeviceAccelerationStructureFeaturesKhr), + ... + }; +} +``` + +### StructureTypes (Optional) + +The `StructureTypes` is the reverse mapping of `ClrTypes` and is likewise trivial to generate. + +```csharp +public struct Chain : IChainable +{ + ... + /// + /// Provides a mapping from the to the corresponding . + /// + public static readonly IReadOnlyDictionary StructureTypes = + new Dictionary + { + [typeof(DeviceCreateInfo)] = StructureType.DeviceCreateInfo, + [typeof(PhysicalDeviceFeatures2)] = StructureType.PhysicalDeviceFeatures2, + [typeof(PhysicalDeviceDescriptorIndexingFeatures)]= StructureType.PhysicalDeviceDescriptorIndexingFeatures, + [typeof(PhysicalDeviceAccelerationStructureFeaturesKhr)] = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr + ... + }; +} +``` + +## Extension Methods + +The following extension methods are not auto-generated and so can be added simply. + +### ClrType() + +Gets the corresponding `ClrType` for a `StructureTYpe`. + +```csharp +public static class ChainExtensions +{ + ... + /// + /// Gets the corresponding for a , if any. + /// + /// The structure type. + /// The corresponding for , if any; otherwise, + /// . + public static Type ClrType(this StructureType structureType) + { + return Chain.ClrTypes[structureType]; + } +} +``` + +Usage: + +```csharp +Assert.Equal(typeof(DeviceCreateInfo), StructureType.DeviceCreateInfo.ClrType()); +``` + +### StructureType() (Optional) + +Gets the corresponding `ClrType` for a `StructureTYpe`. + +```csharp +public static class ChainExtensions +{ + ... + /// + /// Gets the corresponding for a , if any. + /// + /// The CLR type. + /// The corresponding for , if any; otherwise, + /// . + public static StructureType? StructureType(this Type type) + { + return Chain.StructureTypes.TryGetValue(type, out var structureType) ? structureType : null; + } +} +``` + +Usage: + +```csharp +Assert.Equal(StructureType.DeviceCreateInfo, typeof(DeviceCreateInfo).StructureType()); +Assert.Null(typeof(PhysicalDeviceFeatures).StructureType()); +``` + +### IsChainStart() + +Tests whether the `StructureType` or `Type` can be used at the start of a chain: + +```csharp +public static class ChainExtensions +{ + ... + /// + /// Whether the can start a chain. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainStart(this StructureType type) + { + return Chain.Extenders.ContainsKey(type); + } + + /// + /// Whether the can start a chain. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainStart(this Type type) + { + return Chain.StructureTypes.TryGetValue(type, out var structureType) && + Chain.Extenders.ContainsKey(structureType); + } +} +``` + +Usage: + +```csharp +Assert.True(StructureType.DeviceCreateInfo.IsChainStart()); +Assert.True(typeof(DeviceCreateInfo).IsChainStart()); +Assert.False(StructureType.PhysicalDeviceDescriptorIndexingFeatures.IsChainStart()); +Assert.False(typeof(PhysicalDeviceDescriptorIndexingFeatures).IsChainStart()); +``` + +### IsChainable() + +Tests whether the `StructureType` or `Type` can be used in a chain: + +```csharp +public static class ChainExtensions +{ + ... + /// + /// Whether the is chainable. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainable(this StructureType type) + { + return Chain.Extenders.ContainsKey(type) || + Chain.Extensions.ContainsKey(type); + } + + /// + /// Whether the is chainable. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainable(this Type type) + { + return Chain.StructureTypes.TryGetValue(type, out var structureType) && + (Chain.Extenders.ContainsKey(structureType) || Chain.Extensions.ContainsKey(structureType)); + } +} +``` + +Usage: + +```csharp +Assert.True(StructureType.DeviceCreateInfo.IsChainable()); +Assert.True(typeof(DeviceCreateInfo).IsChainable()); +Assert.True(StructureType.PhysicalDeviceDescriptorIndexingFeatures.IsChainable()); +Assert.True(typeof(PhysicalDeviceDescriptorIndexingFeatures).IsChainable()); +``` + +### CanExtend() + +Tests whether the `StructureType` or `Type` can extend the corresponding type: + +```csharp +public static class ChainExtensions +{ + ... + + /// + /// Whether the current can extend the . + /// + /// The to test. + /// The of the chain. + /// if the can extend the ; otherwise, false. + /// + public static bool CanExtend(this StructureType next, StructureType chain) + { + return Chain.Extensions.TryGetValue(next, out var extensions) && extensions.Contains(chain); + } + + /// + /// Whether the current can extend the . + /// + /// The to test. + /// The of the chain. + /// if the can extend the ; otherwise, false. + /// + public static bool CanExtend(this Type next, Type chain) + { + return + Chain.StructureTypes.TryGetValue(next, out var nextType) && + Chain.StructureTypes.TryGetValue(chain, out var chainType) && + Chain.Extensions.TryGetValue(nextType, out var extensions) && + extensions.Contains(chainType); + } +} +``` + +Usage: + +```csharp +Assert.True(StructureType.PhysicalDeviceFeatures2.CanExtend(StructureType.DeviceCreateInfo)); +Assert.False(StructureType.DeviceCreateInfo.CanExtend(StructureType.PhysicalDeviceFeatures2)); +Assert.True(typeof(PhysicalDeviceFeatures2).CanExtend(typeof(DeviceCreateInfo))); +Assert.False(typeof(DeviceCreateInfo).CanExtend(typeof(PhysicalDeviceFeatures2))); +``` + +### CanBeExtendedBy() + +Tests whether the `StructureType` or `Type` can be extended by the corresponding type: + +```csharp +public static class ChainExtensions +{ + ... + + /// + /// Whether the current can be extended by the . + /// + /// The of the chain. + /// The to test. + /// if the can be extended the ; otherwise, false. + /// + public static bool CanBeExtendedBy(this StructureType chain, StructureType next) + { + return Chain.Extenders.TryGetValue(chain, out var extenders) && extenders.Contains(next); + } + + /// + /// Whether the current can be extended by the . + /// + /// The of the chain. + /// The to test. + /// if the can extend the ; otherwise, false. + /// + public static bool CanBeExtendedBy(this Type chain, Type next) + { + return + Chain.StructureTypes.TryGetValue(next, out var nextType) && + Chain.StructureTypes.TryGetValue(chain, out var chainType) && + Chain.Extenders.TryGetValue(chainType, out var extenders) && + extenders.Contains(nextType); + } +} +``` + +Usage: + +```csharp +Assert.False(StructureType.PhysicalDeviceFeatures2.CanBeExtendedBy(StructureType.DeviceCreateInfo)); +Assert.True(StructureType.DeviceCreateInfo.CanBeExtendedBy(StructureType.PhysicalDeviceFeatures2)); +Assert.False(typeof(PhysicalDeviceFeatures2).CanBeExtendedBy(typeof(DeviceCreateInfo))); +Assert.True(typeof(DeviceCreateInfo).CanBeExtendedBy(typeof(PhysicalDeviceFeatures2))); +``` \ No newline at end of file diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj index 9353923378..c61c1205b8 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/PrototypeStructChaining.Test.csproj @@ -10,9 +10,9 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -24,11 +24,11 @@ - + - + diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainMetadata.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainMetadata.cs new file mode 100644 index 0000000000..f823b0bdf5 --- /dev/null +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainMetadata.cs @@ -0,0 +1,58 @@ +using System; +using System.Linq; +using Silk.Net.Vulkan; +using Xunit; + +namespace PrototypeStructChaining.Test; + +public class TestChainMetadata +{ + [Fact] + public void TestClrType() + { + Assert.Equal(typeof(DeviceCreateInfo), StructureType.DeviceCreateInfo.ClrType()); + } + + [Fact] + public void TestStructureType() + { + Assert.Equal(StructureType.DeviceCreateInfo, typeof(DeviceCreateInfo).StructureType()); + Assert.Null(typeof(PhysicalDeviceFeatures).StructureType()); + } + + [Fact] + public void TestIsChainStart() + { + Assert.True(StructureType.DeviceCreateInfo.IsChainStart()); + Assert.True(typeof(DeviceCreateInfo).IsChainStart()); + Assert.False(StructureType.PhysicalDeviceDescriptorIndexingFeatures.IsChainStart()); + Assert.False(typeof(PhysicalDeviceDescriptorIndexingFeatures).IsChainStart()); + } + + [Fact] + public void TestIsChainable() + { + Assert.True(StructureType.DeviceCreateInfo.IsChainable()); + Assert.True(typeof(DeviceCreateInfo).IsChainable()); + Assert.True(StructureType.PhysicalDeviceDescriptorIndexingFeatures.IsChainable()); + Assert.True(typeof(PhysicalDeviceDescriptorIndexingFeatures).IsChainable()); + } + + [Fact] + public void TestCanExtend() + { + Assert.True(StructureType.PhysicalDeviceFeatures2.CanExtend(StructureType.DeviceCreateInfo)); + Assert.False(StructureType.DeviceCreateInfo.CanExtend(StructureType.PhysicalDeviceFeatures2)); + Assert.True(typeof(PhysicalDeviceFeatures2).CanExtend(typeof(DeviceCreateInfo))); + Assert.False(typeof(DeviceCreateInfo).CanExtend(typeof(PhysicalDeviceFeatures2))); + } + + [Fact] + public void TestCanBeExtendedBy() + { + Assert.False(StructureType.PhysicalDeviceFeatures2.CanBeExtendedBy(StructureType.DeviceCreateInfo)); + Assert.True(StructureType.DeviceCreateInfo.CanBeExtendedBy(StructureType.PhysicalDeviceFeatures2)); + Assert.False(typeof(PhysicalDeviceFeatures2).CanBeExtendedBy(typeof(DeviceCreateInfo))); + Assert.True(typeof(DeviceCreateInfo).CanBeExtendedBy(typeof(PhysicalDeviceFeatures2))); + } +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs index 2ccadfa81b..d8eab9cffe 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs @@ -14,7 +14,7 @@ public unsafe void TestAddNext() // AddNext will create an empty struct, with the correct SType (as well as ensuring the // chain's SType is coerced correctly. .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) - .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); // Ensure all pointers set correctly Assert.Equal((nint) (&indexingFeatures), (nint) features2.PNext); @@ -63,7 +63,7 @@ public unsafe void TestSetNext() { ShaderInputAttachmentArrayDynamicIndexing = true }; - var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKHR + var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKhr { AccelerationStructure = true }; diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs index 268447d33f..e1504b67d3 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs @@ -11,7 +11,7 @@ public class TestManagedChains public unsafe void TestManagedChain() { using var chain = new ManagedChain(); + PhysicalDeviceAccelerationStructureFeaturesKhr>(); // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); @@ -63,7 +63,7 @@ public unsafe void TestManagedChainReplaceHead() public unsafe void TestManagedChainReplaceMiddle() { using var chain = new ManagedChain + PhysicalDeviceAccelerationStructureFeaturesKhr> ( item1: new PhysicalDeviceDescriptorIndexingFeatures { @@ -163,7 +163,7 @@ public unsafe void TestManagedChainAppend() // Check flag set Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); - using var newChain = chain.Append(); + using var newChain = chain.Append(); // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, newChain.Head.SType); @@ -190,9 +190,9 @@ public unsafe void TestManagedChainTruncate() ManagedChain.Create< PhysicalDeviceFeatures2, PhysicalDeviceDescriptorIndexingFeatures, - PhysicalDeviceAccelerationStructureFeaturesKHR> + PhysicalDeviceAccelerationStructureFeaturesKhr> ( - item2: new PhysicalDeviceAccelerationStructureFeaturesKHR + item2: new PhysicalDeviceAccelerationStructureFeaturesKhr {AccelerationStructure = true} ); @@ -240,12 +240,12 @@ public unsafe void TestManagedChainLoad() PhysicalDeviceFeatures2 .Chain(out var unmanagedChain) .SetNext(ref indexingFeatures) - .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); // Loads a new managed chain from an unmanaged chain using var managedChain = new ManagedChain(out var errors, unmanagedChain); + PhysicalDeviceAccelerationStructureFeaturesKhr>(out var errors, unmanagedChain); // Check we had no loading errors Assert.Equal("", errors); @@ -276,16 +276,16 @@ public void TestManagedChainLoadWithError() .Chain(out var unmanagedChain) .AddNext(out PhysicalDeviceFeatures2 features2) .SetNext(ref indexingFeatures) - .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); // Loads a new managed chain from an unmanaged chain using var managedChain = ManagedChain.Load< DeviceCreateInfo, // Note we are supplied a PhysicalDeviceFeatures2 here from the unmanaged chain - PhysicalDeviceAccelerationStructureFeaturesKHR, + PhysicalDeviceAccelerationStructureFeaturesKhr, PhysicalDeviceDescriptorIndexingFeatures, - PhysicalDeviceAccelerationStructureFeaturesKHR, + PhysicalDeviceAccelerationStructureFeaturesKhr, // Note that the unmanaged chain did not supply a 5th entry PhysicalDeviceFeatures2>(out var errors, unmanagedChain); @@ -312,7 +312,7 @@ public void TestManagedChainLoadWithErrorTooLong() .Chain(out var unmanagedChain) .AddNext(out PhysicalDeviceFeatures2 features2) .SetNext(ref indexingFeatures) - .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); // Try loading a shorter managed chain using var managedChain = @@ -332,7 +332,7 @@ public void TestManagedChainLoadWithErrorTooLong() public void TestReadOnlyList() { using var chain = new ManagedChain(); + PhysicalDeviceAccelerationStructureFeaturesKhr>(); Assert.Equal(3, chain.Count); @@ -349,14 +349,14 @@ public void TestReadOnlyList() // Check concrete types Assert.IsType(structures[0]); Assert.IsType(structures[1]); - Assert.IsType(structures[2]); + Assert.IsType(structures[2]); } [Fact] public void TestDeconstructor() { using var chain = new ManagedChain(); + PhysicalDeviceAccelerationStructureFeaturesKhr>(); var (physicalDeviceFeatures2, indexingFeatures, accelerationStructureFeaturesKhr) = chain; diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs index 4764a845bb..b4a101b44b 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs @@ -11,6 +11,70 @@ namespace Silk.Net.Vulkan; /// public struct Chain : IChainable { + /// + /// Provides a set of all the s that can be extended by a . + /// + public static readonly IReadOnlyDictionary> Extensions = + new Dictionary> + { + [StructureType.PhysicalDeviceFeatures2] = new HashSet + { + StructureType.DeviceCreateInfo + }, + [StructureType.PhysicalDeviceDescriptorIndexingFeatures] = new HashSet + { + StructureType.PhysicalDeviceFeatures2, + StructureType.DeviceCreateInfo + }, + [StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr] = new HashSet + { + StructureType.PhysicalDeviceFeatures2, + StructureType.DeviceCreateInfo + } + }; + + /// + /// Provides a set of all the s that can extend a . + /// + public static readonly IReadOnlyDictionary> Extenders = + new Dictionary> + { + [StructureType.DeviceCreateInfo] = new HashSet + { + StructureType.PhysicalDeviceFeatures2, StructureType.PhysicalDeviceDescriptorIndexingFeatures, + StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr + }, + [StructureType.PhysicalDeviceFeatures2] = new HashSet + { + StructureType.PhysicalDeviceDescriptorIndexingFeatures, + StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr + } + }; + + /// + /// Provides a mapping from the to the corresponding . + /// + public static readonly IReadOnlyDictionary ClrTypes = + new Dictionary + { + [StructureType.DeviceCreateInfo] = typeof(DeviceCreateInfo), + [StructureType.PhysicalDeviceFeatures2] = typeof(PhysicalDeviceFeatures2), + [StructureType.PhysicalDeviceDescriptorIndexingFeatures]= typeof(PhysicalDeviceDescriptorIndexingFeatures), + [StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr] = typeof(PhysicalDeviceAccelerationStructureFeaturesKhr) + }; + + /// + /// Provides a mapping from the to the corresponding . + /// + public static readonly IReadOnlyDictionary StructureTypes = + new Dictionary + { + [typeof(DeviceCreateInfo)] = StructureType.DeviceCreateInfo, + [typeof(PhysicalDeviceFeatures2)] = StructureType.PhysicalDeviceFeatures2, + [typeof(PhysicalDeviceDescriptorIndexingFeatures)]= StructureType.PhysicalDeviceDescriptorIndexingFeatures, + [typeof(PhysicalDeviceAccelerationStructureFeaturesKhr)] = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr + }; + /// /// The structure type. /// diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs index 51c36f6393..e4553fa546 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs @@ -22,7 +22,7 @@ public static class ChainExtensions /// { /// ShaderInputAttachmentArrayDynamicIndexing = true /// }; - /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKHR + /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKhr /// { /// AccelerationStructure = true /// }; @@ -92,7 +92,7 @@ public static unsafe ref TChain SetNext /// PhysicalDeviceFeatures2 /// .Chain(out var features2) /// .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) - /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); /// /// Note, the value is always added, even if an equivalent value is added in the chain already. Use /// to only add if not already present. @@ -203,4 +203,129 @@ public static unsafe int IndexOf(this ref TChain chain, ref TNext return -1; } + + /// + /// Gets the corresponding for a , if any. + /// + /// The structure type. + /// The corresponding for , if any; otherwise, + /// . + public static Type ClrType(this StructureType structureType) + { + return Chain.ClrTypes[structureType]; + } + + /// + /// Gets the corresponding for a , if any. + /// + /// The CLR type. + /// The corresponding for , if any; otherwise, + /// . + public static StructureType? StructureType(this Type type) + { + return Chain.StructureTypes.TryGetValue(type, out var structureType) ? structureType : null; + } + + /// + /// Whether the can start a chain. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainStart(this StructureType type) + { + return Chain.Extenders.ContainsKey(type); + } + + /// + /// Whether the can start a chain. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainStart(this Type type) + { + return Chain.StructureTypes.TryGetValue(type, out var structureType) && + Chain.Extenders.ContainsKey(structureType); + } + + /// + /// Whether the is chainable. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainable(this StructureType type) + { + return Chain.Extenders.ContainsKey(type) || + Chain.Extensions.ContainsKey(type); + } + + /// + /// Whether the is chainable. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainable(this Type type) + { + return Chain.StructureTypes.TryGetValue(type, out var structureType) && + (Chain.Extenders.ContainsKey(structureType) || Chain.Extensions.ContainsKey(structureType)); + } + + /// + /// Whether the current can extend the . + /// + /// The to test. + /// The of the chain. + /// if the can extend the ; otherwise, false. + /// + public static bool CanExtend(this StructureType next, StructureType chain) + { + return Chain.Extensions.TryGetValue(next, out var extensions) && extensions.Contains(chain); + } + + /// + /// Whether the current can extend the . + /// + /// The to test. + /// The of the chain. + /// if the can extend the ; otherwise, false. + /// + public static bool CanExtend(this Type next, Type chain) + { + return + Chain.StructureTypes.TryGetValue(next, out var nextType) && + Chain.StructureTypes.TryGetValue(chain, out var chainType) && + Chain.Extensions.TryGetValue(nextType, out var extensions) && + extensions.Contains(chainType); + } + + /// + /// Whether the current can be extended by the . + /// + /// The of the chain. + /// The to test. + /// if the can be extended the ; otherwise, false. + /// + public static bool CanBeExtendedBy(this StructureType chain, StructureType next) + { + return Chain.Extenders.TryGetValue(chain, out var extenders) && extenders.Contains(next); + } + + /// + /// Whether the current can be extended by the . + /// + /// The of the chain. + /// The to test. + /// if the can extend the ; otherwise, false. + /// + public static bool CanBeExtendedBy(this Type chain, Type next) + { + return + Chain.StructureTypes.TryGetValue(next, out var nextType) && + Chain.StructureTypes.TryGetValue(chain, out var chainType) && + Chain.Extenders.TryGetValue(chainType, out var extenders) && + extenders.Contains(nextType); + } } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs similarity index 90% rename from src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs rename to src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs index bd7fdeb97e..30cec6947a 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKHR.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs @@ -1,6 +1,6 @@ namespace Silk.Net.Vulkan; -public struct PhysicalDeviceAccelerationStructureFeaturesKHR : +public struct PhysicalDeviceAccelerationStructureFeaturesKhr : IExtendsChain, IExtendsChain { @@ -15,7 +15,7 @@ public struct PhysicalDeviceAccelerationStructureFeaturesKHR : // NOTE Truncated for example - public unsafe PhysicalDeviceAccelerationStructureFeaturesKHR( + public unsafe PhysicalDeviceAccelerationStructureFeaturesKhr( StructureType? sType = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, void* pNext = null, bool? accelerationStructure = null) From 374d85eee8bb198e9f6065e92d838f6116f6e794 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Tue, 9 Nov 2021 09:49:05 +0000 Subject: [PATCH 29/34] docs: Added suggestion for specific chain interfaces --- ...Struct Chaining - #2 Unmanaged Chaining.md | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md index 513cd4487d..d00ec4764a 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md @@ -120,8 +120,12 @@ presence of the `ManagedChain` classes from [the proposal for managed chains](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%233%20Managed%20Chaining.md), along with a well documented API should highlight the danger of such practices. -Indeed, it is important to remember that such dangers are already part of the existing implementation and are a feature of -using unmanaged pointers in .NET rather than a limitation of this proposal. +Indeed, it is important to remember that such dangers are already part of the existing implementation and are a feature +of using unmanaged pointers in .NET rather than a limitation of this proposal. + +To be discussed: + +- Whether to include [specific chain interfaces](#chain-interfaces-optional). # Usage @@ -494,3 +498,23 @@ public static unsafe ref [StrucType] Chain( return ref capture; } ``` + +### Chain interfaces (Optional) + +As a useful optional extra, whenever an `IChainStart` struct is found, a corresponding `I[StructName]Chain` is created, +that extends from `IChainable`, e.g.: + +```csharp +namespace Silk.Net.Vulkan; + +/// +/// Marks a chainable struct as being part of the `DeviceCreateInfo` chain. +/// +public interface IDeviceCreateInfoChain : IChainable +{ +} +``` + +This interface is then added to the corresponding `IChainStart` _and_ any struct that implements the +corresponding `IExtendsChain`. The primary benefit of this approach is to make it significantly easier to write +code that accepts any part of a specific chain (including the head). \ No newline at end of file From 866f2dcdcc7817995e9fb633213e7630d510ee35 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Tue, 9 Nov 2021 11:54:16 +0000 Subject: [PATCH 30/34] docs: Updated to use `BaseInStructure` * `Chain` was replaced by `BaseInStructure`, which is supplied by the Vulkan Specification already. * `ChainExtensions` was renamed to `Chain`. --- ... Chaining - #1 StructureType correction.md | 10 +- ...Struct Chaining - #2 Unmanaged Chaining.md | 20 +- ...ining - #4 Chaining Metadata extensions.md | 16 +- .../TestChains.cs | 6 +- .../TestCompilation.cs | 2 +- .../BaseInStructure.cs | 37 + .../PrototypeStructChaining/Chain.cs | 389 +++- .../ChainExtensions.cs | 331 --- .../DeviceCreateInfo.cs | 4 +- .../PrototypeStructChaining/IChainStart.cs | 2 +- .../PrototypeStructChaining/IChainable.cs | 4 +- .../ManagedChain.gen.cs | 1896 ++++++++--------- .../ManagedChain.gen.tt | 36 +- ...lDeviceAccelerationStructureFeaturesKhr.cs | 4 +- ...hysicalDeviceDescriptorIndexingFeatures.cs | 4 +- .../PhysicalDeviceFeatures2.cs | 4 +- 16 files changed, 1384 insertions(+), 1381 deletions(-) create mode 100644 src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/BaseInStructure.cs delete mode 100644 src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md index a1532210f5..0af0ccad20 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md @@ -24,10 +24,6 @@ correctly set when passing to Vulkan, and to provide a mechanism for doing so. - The `IStructuredType` interface will usually not be implemented directly, instead `IChainable` (from the [unmanaged chaining proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md)) will extend this interface. -- The BuildTools should instead only add this interface to any structure that meets the above constraint (the structure - has a `StructureType SType` field) that _doesn't_ already add the `IChainable` interface. Though I believe this - scenario won't occur in the current Vulkan specification, we'd need to check all valid StructureType structures to - confirm, and regardless, writing the code to add the interface in such scenarios will future proof it. - Whenever the `IStructuredType` is added to an interface (either directly or indirectly) the corresponding `StructureType()` method should also be explicitly implemented ([see below](#istructuretype-implementation)). @@ -40,6 +36,8 @@ correctly set when passing to Vulkan, and to provide a mechanism for doing so. - To be clear, this proposal does not need to guarantee that the `SType` field is in position 0 (i.e. first), that requirement is only necessary to implement the functionality [proposed by the unmanaged chaining system](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) +- Not all structures exposed by Vulkan have a default value for the `SType`, (e.g. `BaseOutStructure` and `BaseInStructure`), + where no default is available, the `StructureType()` method only returns the current value, rather than setting it. # Implementation Notes @@ -72,7 +70,7 @@ public interface IStructuredType /// Gets the structured type's enum value. /// /// - /// Retrieving the also ensures it is set to the correct value. + /// Retrieving the also ensures it is set to the correct value (if any). /// StructureType StructureType(); } @@ -81,7 +79,7 @@ public interface IStructuredType ### IStructureType implementation Each struct generated that implements `IStructuredType` should also have the following code auto-generated, to -explicitly implement the interface. The method sets and returns the `SType` correctly for the current structure. +explicitly implement the interface. The method sets and returns the `SType` correctly (if any) for the current structure. ```csharp /// diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md index d00ec4764a..8b179e185c 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md @@ -19,11 +19,11 @@ from [Proposal - Vulkan Struct Chaining - #1 StructureType correction](Proposal% and so the explicit implementation of `IChainable.StructureType()` from [that proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md#istructuretype-implementation) is triggerred for the structure, providing a mechanism for ensuring the `SType` is correctly set. It then exposes -a `Chain* PNext { get; set; }` property for easy access to the next item in the chain. +a `BaseInStructure* PNext { get; set; }` property for easy access to the next item in the chain. The presence of the `IChainable` interface, also acts as a **guarantee** that it is safe to cast any pointer of a struct -implementing it to a pointer to a `Chain` struct, which is a struct which has just the `SType` and `PNext` fields -present. Therefore it is always possible to cast `void* PNext` of an `IChainable` struct to `Chain*`. It is this +implementing it to a pointer to a `BaseInStructure` struct, which is a struct which has just the `SType` and `PNext` fields +present. Therefore it is always possible to cast `void* PNext` of an `IChainable` struct to `BaseInStructure*`. It is this guarantee that requires the position of the fields to be fixed (which they are in practice). However, by ensuring we validate the constraints at build time (when choosing to add the interface), we can prevent downstream bugs occurring at run time. @@ -57,7 +57,7 @@ generated (the static `Chain(out)` method and the explicit `IStructuredType.Stru implementation); as compared to all other `IChainable` structs, which will only have the explicit `IStructuredType.StructureType()` implementation from [Proposal - Vulkan Struct Chaining - #1 StructureType correction](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%231%20StructureType%20correction.md) -and the explicit `Chain* IChainable.PNext { get; set;}` property from this proposal. +and the explicit `BaseInStructure* IChainable.PNext { get; set;}` property from this proposal. The remaining functionality is provided entirely by the following new extension methods: @@ -146,7 +146,7 @@ createinfo.AddNext... ``` -in many cases, we only want to create a default structure for population by the API. To do so, we use the -static `Chain` method like so: +static `BaseInStructure` method like so: ```csharp PhysicalDeviceFeatures2.Chain(out var features2) @@ -158,7 +158,7 @@ This has several advantages: - The structure's `SType` will be correctly set immediately. - The syntax is fluent, and creates more readable code when used with the other chaining methods (see below). -**Note** All the chaining methods return the current start of the chain by reference (including `Chain`). This allows +**Note** All the chaining methods return the current start of the chain by reference (including `BaseInStructure`). This allows each method to scan the entire chain. More importantly, it allows the Type constraints to be checked during compile time to ensure that a type actually extends the chain. One side effect is that `ref Chain(out)` outputs the newly created chain _and_ returns a reference to it. This can cause confusion to less experienced C# devs, for example: @@ -344,7 +344,7 @@ found [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeS ```csharp namespace Silk.Net.Vulkan; -public static class ChainExtensions +public static class Chain { /// /// Replaces a structure in the chain (if present, and is false), or adds it to the end. @@ -442,7 +442,7 @@ public static class ChainExtensions ### Chain Structure -The `Chain` struct makes it easy to access the `SType` and `PNext` of a structure pointed to by `void* PNext`, although +The `BaseInStructure` struct makes it easy to access the `SType` and `PNext` of a structure pointed to by `void* PNext`, although it is used internally, it is useful for consumers of Silk.Net to have access to use in their own scenarios, that is because the `IChainable` interface does not directly expose the underlying `SType` and `PNext` fields; as they are fields (not properties), and this proposal aims to avoid boxing (so we try not to use the interface directly @@ -456,7 +456,7 @@ namespace Silk.Net.Vulkan; /// /// /// Any pointer to a structure marked as can safely be cast to a pointer to this type. -/// In particular, this means that the void* PNext field can always be safely cast to Chain*, providing +/// In particular, this means that the void* PNext field can always be safely cast to BaseInStructure*, providing /// access to the `SType` and `PNext` fields. /// /// @@ -469,7 +469,7 @@ public struct Chain : IChainable /// /// The next struct in the chain, if any; otherwise . /// - public unsafe Chain* PNext; + public unsafe BaseInStructure* PNext; /// /// Note, this cannot coerce the type as 'guaranteed by the `IStructuredType` interface. diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md index bd2ed5db6c..5a1153fcfb 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #4 Chaining Metadata extensions.md @@ -40,13 +40,13 @@ for a given chain, at runtime. To facilitate the most common scenario 4 extensio ## Auto-generated Metadata Structures -The `Extensions` dictionary is added to the `Chain` structure from +The `Extensions` dictionary is added to the `Chain` extensions class from the [unmanaged chaining proposal](Proposal%20-%20Vulkan%20Struct%20Chaining%20-%20%232%20Unmanaged%20Chaining.md) for discoverability. It is a direct mapping of the `structextends` attribute, and is therefore trivial to generate. Below is a cut down example to illustrate what will be generated: ```csharp -public struct Chain : IChainable +public static class Chain : IChainable { ... /// @@ -161,7 +161,7 @@ The following extension methods are not auto-generated and so can be added simpl Gets the corresponding `ClrType` for a `StructureTYpe`. ```csharp -public static class ChainExtensions +public static class Chain { ... /// @@ -188,7 +188,7 @@ Assert.Equal(typeof(DeviceCreateInfo), StructureType.DeviceCreateInfo.ClrType()) Gets the corresponding `ClrType` for a `StructureTYpe`. ```csharp -public static class ChainExtensions +public static class Chain { ... /// @@ -216,7 +216,7 @@ Assert.Null(typeof(PhysicalDeviceFeatures).StructureType()); Tests whether the `StructureType` or `Type` can be used at the start of a chain: ```csharp -public static class ChainExtensions +public static class Chain { ... /// @@ -258,7 +258,7 @@ Assert.False(typeof(PhysicalDeviceDescriptorIndexingFeatures).IsChainStart()); Tests whether the `StructureType` or `Type` can be used in a chain: ```csharp -public static class ChainExtensions +public static class Chain { ... /// @@ -301,7 +301,7 @@ Assert.True(typeof(PhysicalDeviceDescriptorIndexingFeatures).IsChainable()); Tests whether the `StructureType` or `Type` can extend the corresponding type: ```csharp -public static class ChainExtensions +public static class Chain { ... @@ -349,7 +349,7 @@ Assert.False(typeof(DeviceCreateInfo).CanExtend(typeof(PhysicalDeviceFeatures2)) Tests whether the `StructureType` or `Type` can be extended by the corresponding type: ```csharp -public static class ChainExtensions +public static class Chain { ... diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs index d8eab9cffe..45c1e5b66d 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs @@ -9,7 +9,7 @@ public class TestChains public unsafe void TestAddNext() { PhysicalDeviceFeatures2 - // The Chain method, is a convenient static, to provide a consistent syntax. + // The BaseInStructure method, is a convenient static, to provide a consistent syntax. .Chain(out var features2) // AddNext will create an empty struct, with the correct SType (as well as ensuring the // chain's SType is coerced correctly. @@ -39,7 +39,7 @@ public unsafe void TestAddNext() public unsafe void TestTryAddNext() { PhysicalDeviceFeatures2 - // The Chain method, is a convenient static, to provide a consistent syntax. + // The BaseInStructure method, is a convenient static, to provide a consistent syntax. .Chain(out var features2) // AddNext will create an empty struct, with the correct SType (as well as ensuring the // chain's SType is coerced correctly. @@ -164,7 +164,7 @@ public unsafe void TestSetNextAlwaysAdd() [Fact] public unsafe void TestWithoutChain() { - // We don't have to use the Chain() pattern, as we can start with an existing struct + // We don't have to use the BaseInStructure() pattern, as we can start with an existing struct var createInfo = new DeviceCreateInfo { Flags = 1U diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs index e8e9163d03..abf2e22595 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs @@ -75,7 +75,7 @@ public void TestCantAddUnsupportedNext() Assert.Single(diagnostics); var error = diagnostics.First(); - // error CS0315: The type 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' cannot be used as type parameter 'TChain' in the generic type or method 'ChainExtensions.AddNext(ref TChain, out TNext)'. There is no boxing conversion from 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' to 'Silk.Net.Vulkan.IChainable'. + // error CS0315: The type 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' cannot be used as type parameter 'TChain' in the generic type or method 'Chain.AddNext(ref TChain, out TNext)'. There is no boxing conversion from 'Silk.Net.Vulkan.PhysicalDeviceFeatures2' to 'Silk.Net.Vulkan.IChainable'. Assert.Equal("CS0315", error.Id); } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/BaseInStructure.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/BaseInStructure.cs new file mode 100644 index 0000000000..dee01f2685 --- /dev/null +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/BaseInStructure.cs @@ -0,0 +1,37 @@ +namespace Silk.Net.Vulkan; + +/// +/// Header struct of all structs. +/// +/// +/// Any pointer to a structure marked as can safely be cast to a pointer to this type. +/// In particular, this means that the void* PNext field can always be safely cast to BaseInStructure*, providing +/// access to the `SType` and `PNext` fields. +/// +/// +public struct BaseInStructure : IChainable +{ + /// + /// The structure type. + /// + public StructureType SType; + + /// + /// The next struct in the chain, if any; otherwise . + /// + public unsafe void* PNext; + + /// + /// Note, this cannot coerce the type as 'guaranteed by the `IStructuredType` interface. + StructureType IStructuredType.StructureType() + { + return SType; + } + + /// + unsafe BaseInStructure* IChainable.PNext + { + get => (BaseInStructure*) PNext; + set => PNext = value; + } +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs index b4a101b44b..75106005dc 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs @@ -1,53 +1,214 @@ +using System.Runtime.CompilerServices; + namespace Silk.Net.Vulkan; -/// -/// Header struct of all structs. -/// -/// -/// Any pointer to a structure marked as can safely be cast to a pointer to this type. -/// In particular, this means that the void* PNext field can always be safely cast to Chain*, providing -/// access to the `SType` and `PNext` fields. -/// -/// -public struct Chain : IChainable +public static class Chain { + /// + /// Replaces a structure in the chain (if present, and is false), or adds it to the end. + /// + /// The current chain + /// A reference to the structure to update + /// Always adds to the end of the chain, even if an equivalent structure is present. + /// The type of the current chain + /// The type of the value + /// A reference to the value value in the chain + /// + /// Note that both the supplied chain, and the supplied value will have their `SType` correctly set. Further, + /// the supplied structure's will be overwritten. + /// To use + /// + /// var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + /// { + /// ShaderInputAttachmentArrayDynamicIndexing = true + /// }; + /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKhr + /// { + /// AccelerationStructure = true + /// }; + /// + /// PhysicalDeviceFeatures2 + /// .BaseInStructure(out var features2) + /// .SetNext(ref indexingFeatures) + /// .SetNext(ref accelerationStructureFeaturesKhr); + /// + /// + public static unsafe ref TChain SetNext + ( + this ref TChain chain, + ref TNext value, + bool alwaysAdd = false + ) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain + { + // Ensure structure type of chain and value are set. + chain.StructureType(); + var structureType = value.StructureType(); + + // Find end of chain + var previousPtr = (BaseInStructure*) null; + var currentPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var valuePtr = (BaseInStructure*) Unsafe.AsPointer(ref value); + do + { + var nextPtr = currentPtr->PNext; + if (!alwaysAdd && currentPtr->SType == structureType) + { + // We have an existing structure, replace it. + if (previousPtr is not null) + { + previousPtr->PNext = valuePtr; + } + + valuePtr->PNext = nextPtr; + + return ref chain; + } + + previousPtr = currentPtr; + currentPtr = (BaseInStructure*) nextPtr; + } while (currentPtr is not null); + + // Add value to end of chain + previousPtr->PNext = valuePtr; + valuePtr->PNext = null; + + return ref chain; + } + + /// + /// Adds a structure to the end of the chain. + /// + /// The current chain + /// The structure added to the end of the chain + /// The type of the current chain + /// The type of the structure to add + /// The reference to the chain. + /// + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .BaseInStructure(out var features2) + /// .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); + /// + /// Note, the value is always added, even if an equivalent value is added in the chain already. Use + /// to only add if not already present. + /// + public static unsafe ref TChain AddNext(this ref TChain chain, out TNext next) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain + { + // Ensure structure type of chain is set. + chain.StructureType(); + + // Find end of chain + var currentPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + while (currentPtr->PNext is not null) + { + currentPtr = (BaseInStructure*) currentPtr->PNext; + } + + // Create new entry and set it's structure type + next = default; + next.StructureType(); + currentPtr->PNext = (BaseInStructure*) Unsafe.AsPointer(ref next); + return ref chain; + } + + /// + /// Tries to add a structure to the end of the chain. + /// + /// The current chain + /// The structure added to the end of the chain + /// Whether the structure was actually added + /// The type of the current chain + /// The type of the structure to add + /// The reference to the chain. + /// + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .BaseInStructure(out var features2) + /// .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures, out var added); + /// + /// + public static unsafe ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain + { + // Ensure structure type of chain is set. + chain.StructureType(); + + // Create new entry and get it's structure type + next = default; + var structureType = next.StructureType(); + + // Follow chain + var currentPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + do + { + if (currentPtr->SType == structureType) + { + added = false; + return ref chain; + } + + var nextPtr = currentPtr->PNext; + if (nextPtr is null) + { + break; + } + + currentPtr = (BaseInStructure*) nextPtr; + } while (true); + + currentPtr->PNext = (BaseInStructure*) Unsafe.AsPointer(ref next); + added = true; + return ref chain; + } + /// /// Provides a set of all the s that can be extended by a . /// public static readonly IReadOnlyDictionary> Extensions = new Dictionary> { - [StructureType.PhysicalDeviceFeatures2] = new HashSet + [Vulkan.StructureType.PhysicalDeviceFeatures2] = new HashSet { - StructureType.DeviceCreateInfo + Vulkan.StructureType.DeviceCreateInfo }, - [StructureType.PhysicalDeviceDescriptorIndexingFeatures] = new HashSet + [Vulkan.StructureType.PhysicalDeviceDescriptorIndexingFeatures] = new HashSet { - StructureType.PhysicalDeviceFeatures2, - StructureType.DeviceCreateInfo + Vulkan.StructureType.PhysicalDeviceFeatures2, + Vulkan.StructureType.DeviceCreateInfo }, - [StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr] = new HashSet + [Vulkan.StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr] = new HashSet { - StructureType.PhysicalDeviceFeatures2, - StructureType.DeviceCreateInfo + Vulkan.StructureType.PhysicalDeviceFeatures2, + Vulkan.StructureType.DeviceCreateInfo } }; - + /// /// Provides a set of all the s that can extend a . /// public static readonly IReadOnlyDictionary> Extenders = new Dictionary> { - [StructureType.DeviceCreateInfo] = new HashSet + [Vulkan.StructureType.DeviceCreateInfo] = new HashSet { - StructureType.PhysicalDeviceFeatures2, StructureType.PhysicalDeviceDescriptorIndexingFeatures, - StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr + Vulkan.StructureType.PhysicalDeviceFeatures2, + Vulkan.StructureType.PhysicalDeviceDescriptorIndexingFeatures, + Vulkan.StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr }, - [StructureType.PhysicalDeviceFeatures2] = new HashSet + [Vulkan.StructureType.PhysicalDeviceFeatures2] = new HashSet { - StructureType.PhysicalDeviceDescriptorIndexingFeatures, - StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr + Vulkan.StructureType.PhysicalDeviceDescriptorIndexingFeatures, + Vulkan.StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr } }; @@ -57,10 +218,12 @@ public struct Chain : IChainable public static readonly IReadOnlyDictionary ClrTypes = new Dictionary { - [StructureType.DeviceCreateInfo] = typeof(DeviceCreateInfo), - [StructureType.PhysicalDeviceFeatures2] = typeof(PhysicalDeviceFeatures2), - [StructureType.PhysicalDeviceDescriptorIndexingFeatures]= typeof(PhysicalDeviceDescriptorIndexingFeatures), - [StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr] = typeof(PhysicalDeviceAccelerationStructureFeaturesKhr) + [Vulkan.StructureType.DeviceCreateInfo] = typeof(DeviceCreateInfo), + [Vulkan.StructureType.PhysicalDeviceFeatures2] = typeof(PhysicalDeviceFeatures2), + [Vulkan.StructureType.PhysicalDeviceDescriptorIndexingFeatures] = + typeof(PhysicalDeviceDescriptorIndexingFeatures), + [Vulkan.StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr] = + typeof(PhysicalDeviceAccelerationStructureFeaturesKhr) }; /// @@ -69,33 +232,169 @@ public struct Chain : IChainable public static readonly IReadOnlyDictionary StructureTypes = new Dictionary { - [typeof(DeviceCreateInfo)] = StructureType.DeviceCreateInfo, - [typeof(PhysicalDeviceFeatures2)] = StructureType.PhysicalDeviceFeatures2, - [typeof(PhysicalDeviceDescriptorIndexingFeatures)]= StructureType.PhysicalDeviceDescriptorIndexingFeatures, - [typeof(PhysicalDeviceAccelerationStructureFeaturesKhr)] = StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr + [typeof(DeviceCreateInfo)] = Vulkan.StructureType.DeviceCreateInfo, + [typeof(PhysicalDeviceFeatures2)] = Vulkan.StructureType.PhysicalDeviceFeatures2, + [typeof(PhysicalDeviceDescriptorIndexingFeatures)] = + Vulkan.StructureType.PhysicalDeviceDescriptorIndexingFeatures, + [typeof(PhysicalDeviceAccelerationStructureFeaturesKhr)] = + Vulkan.StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr }; /// - /// The structure type. + /// Returns the index of the in the , if present. + /// + /// The chain + /// The structure value + /// The type of the current chain + /// The type of the value + /// The zero-indexed index if found; otherwise -1. + public static unsafe int IndexOf(this ref TChain chain, ref TNext value) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain + { + // Ensure structure type of chain is set. + chain.StructureType(); + + var index = 0; + var currentPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var valuePtr = (BaseInStructure*) Unsafe.AsPointer(ref value); + // Follow chain + do + { + if (currentPtr == valuePtr) + { + return index; + } + + currentPtr = (BaseInStructure*) currentPtr->PNext; + index++; + } while (currentPtr is not null); + + return -1; + } + + /// + /// Gets the corresponding for a , if any. + /// + /// The structure type. + /// The corresponding for , if any; otherwise, + /// . + public static Type ClrType(this StructureType structureType) + { + return ClrTypes[structureType]; + } + + /// + /// Gets the corresponding for a , if any. + /// + /// The CLR type. + /// The corresponding for , if any; otherwise, + /// . + public static StructureType? StructureType(this Type type) + { + return StructureTypes.TryGetValue(type, out var structureType) ? structureType : null; + } + + /// + /// Whether the can start a chain. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainStart(this StructureType type) + { + return Extenders.ContainsKey(type); + } + + /// + /// Whether the can start a chain. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainStart(this Type type) + { + return StructureTypes.TryGetValue(type, out var structureType) && + Extenders.ContainsKey(structureType); + } + + /// + /// Whether the is chainable. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainable(this StructureType type) + { + return Extenders.ContainsKey(type) || + Extensions.ContainsKey(type); + } + + /// + /// Whether the is chainable. + /// + /// The to test. + /// if the can start a chain; otherwise + /// . + public static bool IsChainable(this Type type) + { + return StructureTypes.TryGetValue(type, out var structureType) && + (Extenders.ContainsKey(structureType) || Extensions.ContainsKey(structureType)); + } + + /// + /// Whether the current can extend the . /// - public StructureType SType; + /// The to test. + /// The of the chain. + /// if the can extend the ; otherwise, false. + /// + public static bool CanExtend(this StructureType next, StructureType chain) + { + return Extensions.TryGetValue(next, out var extensions) && extensions.Contains(chain); + } /// - /// The next struct in the chain, if any; otherwise . + /// Whether the current can extend the . /// - public unsafe Chain* PNext; + /// The to test. + /// The of the chain. + /// if the can extend the ; otherwise, false. + /// + public static bool CanExtend(this Type next, Type chain) + { + return + StructureTypes.TryGetValue(next, out var nextType) && + StructureTypes.TryGetValue(chain, out var chainType) && + Extensions.TryGetValue(nextType, out var extensions) && + extensions.Contains(chainType); + } - /// - /// Note, this cannot coerce the type as 'guaranteed by the `IStructuredType` interface. - StructureType IStructuredType.StructureType() + /// + /// Whether the current can be extended by the . + /// + /// The of the chain. + /// The to test. + /// if the can be extended the ; otherwise, false. + /// + public static bool CanBeExtendedBy(this StructureType chain, StructureType next) { - return SType; + return Extenders.TryGetValue(chain, out var extenders) && extenders.Contains(next); } - /// - unsafe Chain* IChainable.PNext + /// + /// Whether the current can be extended by the . + /// + /// The of the chain. + /// The to test. + /// if the can extend the ; otherwise, false. + /// + public static bool CanBeExtendedBy(this Type chain, Type next) { - get => (Chain*) PNext; - set => PNext = value; + return + StructureTypes.TryGetValue(next, out var nextType) && + StructureTypes.TryGetValue(chain, out var chainType) && + Extenders.TryGetValue(chainType, out var extenders) && + extenders.Contains(nextType); } } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs deleted file mode 100644 index e4553fa546..0000000000 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs +++ /dev/null @@ -1,331 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Silk.Net.Vulkan; - -public static class ChainExtensions -{ - /// - /// Replaces a structure in the chain (if present, and is false), or adds it to the end. - /// - /// The current chain - /// A reference to the structure to update - /// Always adds to the end of the chain, even if an equivalent structure is present. - /// The type of the current chain - /// The type of the value - /// A reference to the value value in the chain - /// - /// Note that both the supplied chain, and the supplied value will have their `SType` correctly set. Further, - /// the supplied structure's will be overwritten. - /// To use - /// - /// var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures - /// { - /// ShaderInputAttachmentArrayDynamicIndexing = true - /// }; - /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKhr - /// { - /// AccelerationStructure = true - /// }; - /// - /// PhysicalDeviceFeatures2 - /// .Chain(out var features2) - /// .SetNext(ref indexingFeatures) - /// .SetNext(ref accelerationStructureFeaturesKhr); - /// - /// - public static unsafe ref TChain SetNext - ( - this ref TChain chain, - ref TNext value, - bool alwaysAdd = false - ) - where TChain : struct, IChainStart - where TNext : struct, IExtendsChain - { - // Ensure structure type of chain and value are set. - chain.StructureType(); - var structureType = value.StructureType(); - - // Find end of chain - var previousPtr = (Chain*) null; - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - var valuePtr = (Chain*) Unsafe.AsPointer(ref value); - do - { - var nextPtr = currentPtr->PNext; - if (!alwaysAdd && currentPtr->SType == structureType) - { - // We have an existing structure, replace it. - if (previousPtr is not null) - { - previousPtr->PNext = valuePtr; - } - - valuePtr->PNext = nextPtr; - - return ref chain; - } - - previousPtr = currentPtr; - currentPtr = nextPtr; - } while (currentPtr is not null); - - // Add value to end of chain - previousPtr->PNext = valuePtr; - valuePtr->PNext = null; - - return ref chain; - } - - /// - /// Adds a structure to the end of the chain. - /// - /// The current chain - /// The structure added to the end of the chain - /// The type of the current chain - /// The type of the structure to add - /// The reference to the chain. - /// - /// Note that both the supplied chain, and the added structure will have their `SType` correctly set - /// To use specify the output type required, e.g.: - /// - /// PhysicalDeviceFeatures2 - /// .Chain(out var features2) - /// .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) - /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); - /// - /// Note, the value is always added, even if an equivalent value is added in the chain already. Use - /// to only add if not already present. - /// - public static unsafe ref TChain AddNext(this ref TChain chain, out TNext next) - where TChain : struct, IChainStart - where TNext : struct, IExtendsChain - { - // Ensure structure type of chain is set. - chain.StructureType(); - - // Find end of chain - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - while (currentPtr->PNext is not null) - { - currentPtr = currentPtr->PNext; - } - - // Create new entry and set it's structure type - next = default; - next.StructureType(); - currentPtr->PNext = (Chain*) Unsafe.AsPointer(ref next); - return ref chain; - } - - /// - /// Tries to add a structure to the end of the chain. - /// - /// The current chain - /// The structure added to the end of the chain - /// Whether the structure was actually added - /// The type of the current chain - /// The type of the structure to add - /// The reference to the chain. - /// - /// Note that both the supplied chain, and the added structure will have their `SType` correctly set - /// To use specify the output type required, e.g.: - /// - /// PhysicalDeviceFeatures2 - /// .Chain(out var features2) - /// .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures, out var added); - /// - /// - public static unsafe ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) - where TChain : struct, IChainStart - where TNext : struct, IExtendsChain - { - // Ensure structure type of chain is set. - chain.StructureType(); - - // Create new entry and get it's structure type - next = default; - var structureType = next.StructureType(); - - // Follow chain - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - do - { - if (currentPtr->SType == structureType) - { - added = false; - return ref chain; - } - - var nextPtr = currentPtr->PNext; - if (nextPtr is null) - { - break; - } - - currentPtr = nextPtr; - } while (true); - - currentPtr->PNext = (Chain*) Unsafe.AsPointer(ref next); - added = true; - return ref chain; - } - - /// - /// Returns the index of the in the , if present. - /// - /// The chain - /// The structure value - /// The type of the current chain - /// The type of the value - /// The zero-indexed index if found; otherwise -1. - public static unsafe int IndexOf(this ref TChain chain, ref TNext value) - where TChain : struct, IChainStart - where TNext : struct, IExtendsChain - { - // Ensure structure type of chain is set. - chain.StructureType(); - - var index = 0; - var currentPtr = (Chain*) Unsafe.AsPointer(ref chain); - var valuePtr = (Chain*) Unsafe.AsPointer(ref value); - // Follow chain - do - { - if (currentPtr == valuePtr) - { - return index; - } - - currentPtr = currentPtr->PNext; - index++; - } while (currentPtr is not null); - - return -1; - } - - /// - /// Gets the corresponding for a , if any. - /// - /// The structure type. - /// The corresponding for , if any; otherwise, - /// . - public static Type ClrType(this StructureType structureType) - { - return Chain.ClrTypes[structureType]; - } - - /// - /// Gets the corresponding for a , if any. - /// - /// The CLR type. - /// The corresponding for , if any; otherwise, - /// . - public static StructureType? StructureType(this Type type) - { - return Chain.StructureTypes.TryGetValue(type, out var structureType) ? structureType : null; - } - - /// - /// Whether the can start a chain. - /// - /// The to test. - /// if the can start a chain; otherwise - /// . - public static bool IsChainStart(this StructureType type) - { - return Chain.Extenders.ContainsKey(type); - } - - /// - /// Whether the can start a chain. - /// - /// The to test. - /// if the can start a chain; otherwise - /// . - public static bool IsChainStart(this Type type) - { - return Chain.StructureTypes.TryGetValue(type, out var structureType) && - Chain.Extenders.ContainsKey(structureType); - } - - /// - /// Whether the is chainable. - /// - /// The to test. - /// if the can start a chain; otherwise - /// . - public static bool IsChainable(this StructureType type) - { - return Chain.Extenders.ContainsKey(type) || - Chain.Extensions.ContainsKey(type); - } - - /// - /// Whether the is chainable. - /// - /// The to test. - /// if the can start a chain; otherwise - /// . - public static bool IsChainable(this Type type) - { - return Chain.StructureTypes.TryGetValue(type, out var structureType) && - (Chain.Extenders.ContainsKey(structureType) || Chain.Extensions.ContainsKey(structureType)); - } - - /// - /// Whether the current can extend the . - /// - /// The to test. - /// The of the chain. - /// if the can extend the ; otherwise, false. - /// - public static bool CanExtend(this StructureType next, StructureType chain) - { - return Chain.Extensions.TryGetValue(next, out var extensions) && extensions.Contains(chain); - } - - /// - /// Whether the current can extend the . - /// - /// The to test. - /// The of the chain. - /// if the can extend the ; otherwise, false. - /// - public static bool CanExtend(this Type next, Type chain) - { - return - Chain.StructureTypes.TryGetValue(next, out var nextType) && - Chain.StructureTypes.TryGetValue(chain, out var chainType) && - Chain.Extensions.TryGetValue(nextType, out var extensions) && - extensions.Contains(chainType); - } - - /// - /// Whether the current can be extended by the . - /// - /// The of the chain. - /// The to test. - /// if the can be extended the ; otherwise, false. - /// - public static bool CanBeExtendedBy(this StructureType chain, StructureType next) - { - return Chain.Extenders.TryGetValue(chain, out var extenders) && extenders.Contains(next); - } - - /// - /// Whether the current can be extended by the . - /// - /// The of the chain. - /// The to test. - /// if the can extend the ; otherwise, false. - /// - public static bool CanBeExtendedBy(this Type chain, Type next) - { - return - Chain.StructureTypes.TryGetValue(next, out var nextType) && - Chain.StructureTypes.TryGetValue(chain, out var chainType) && - Chain.Extenders.TryGetValue(chainType, out var extenders) && - extenders.Contains(nextType); - } -} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs index 292c2bb96f..3f6a136559 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs @@ -62,9 +62,9 @@ StructureType IStructuredType.StructureType() } /// - unsafe Chain* IChainable.PNext + unsafe BaseInStructure* IChainable.PNext { - get => (Chain*) PNext; + get => (BaseInStructure*) PNext; set => PNext = value; } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs index 4da9542556..867d9d658a 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs @@ -3,7 +3,7 @@ namespace Silk.Net.Vulkan; /// /// Marks a chainable struct as being allowed at the start of a chain. /// -/// Any will have a corresponding static `Chain(out var chain)` +/// Any will have a corresponding static `BaseInStructure(out var chain)` /// convenience method. public interface IChainStart : IChainable { diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs index 098fd169bc..9b47ca507c 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs @@ -5,8 +5,8 @@ namespace Silk.Net.Vulkan; /// /// Note that any structure marked must start with a /// and a void* field, in that order. This is so that a pointer to it can be coerced -/// to a pointer to a . +/// to a pointer to a . public interface IChainable : IStructuredType { - unsafe Chain* PNext { get; set; } + unsafe BaseInStructure* PNext { get; set; } } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs index def61ff87a..ae81ec1995 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs @@ -1227,18 +1227,18 @@ public unsafe class ManagedChain : ManagedChain /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -1387,18 +1387,18 @@ public unsafe class ManagedChain : ManagedChain /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -1408,7 +1408,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -1448,7 +1448,7 @@ public ManagedChain(TChain head = default, T1 item1 = default) { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -1466,12 +1466,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -1510,7 +1510,7 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); return new ManagedChain(newHeadPtr); } @@ -1535,8 +1535,8 @@ public ManagedChain(ManagedChain previous, T1 item1 = default) Marshal.StructureToPtr(item1, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -1567,7 +1567,7 @@ public ManagedChain Truncate(out T1 item1) // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = null; return new ManagedChain(newHeadPtr); } @@ -1679,18 +1679,18 @@ public unsafe class ManagedChain : ManagedChain /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -1700,7 +1700,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -1721,7 +1721,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -1762,7 +1762,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -1784,12 +1784,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -1808,9 +1808,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -1849,8 +1849,8 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); return new ManagedChain(newHeadPtr); } @@ -1875,9 +1875,9 @@ public ManagedChain(ManagedChain previous, T2 item2 = default) Marshal.StructureToPtr(item2, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -1908,8 +1908,8 @@ public ManagedChain Truncate(out T2 item2) // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -2038,18 +2038,18 @@ public unsafe class ManagedChain : ManagedChain /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -2059,7 +2059,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -2080,7 +2080,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -2101,7 +2101,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -2143,7 +2143,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -2169,12 +2169,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -2193,9 +2193,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -2214,9 +2214,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -2255,9 +2255,9 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); return new ManagedChain(newHeadPtr); } @@ -2282,10 +2282,10 @@ public ManagedChain(ManagedChain previous, T3 item3 = default) Marshal.StructureToPtr(item3, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -2316,9 +2316,9 @@ public ManagedChain Truncate(out T3 item3) // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -2464,18 +2464,18 @@ public unsafe class ManagedChain : ManagedChain /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -2485,7 +2485,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -2506,7 +2506,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -2527,7 +2527,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -2548,7 +2548,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -2591,7 +2591,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -2621,12 +2621,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -2645,9 +2645,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -2666,9 +2666,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -2687,9 +2687,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -2728,10 +2728,10 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); return new ManagedChain(newHeadPtr); } @@ -2756,11 +2756,11 @@ public ManagedChain(ManagedChain previous, T4 item4 = defaul Marshal.StructureToPtr(item4, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -2791,10 +2791,10 @@ public ManagedChain Truncate(out T4 item4) // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -2957,18 +2957,18 @@ public unsafe class ManagedChain : ManagedChain /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -2978,7 +2978,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -2999,7 +2999,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -3020,7 +3020,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -3041,7 +3041,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -3062,7 +3062,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -3106,7 +3106,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -3140,12 +3140,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -3164,9 +3164,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -3185,9 +3185,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -3206,9 +3206,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -3227,9 +3227,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -3268,11 +3268,11 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); return new ManagedChain(newHeadPtr); } @@ -3297,12 +3297,12 @@ public ManagedChain(ManagedChain previous, T5 item5 = de Marshal.StructureToPtr(item5, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -3333,11 +3333,11 @@ public ManagedChain Truncate(out T5 item5) // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -3517,18 +3517,18 @@ public unsafe class ManagedChain : ManagedChain /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -3538,7 +3538,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -3559,7 +3559,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -3580,7 +3580,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -3601,7 +3601,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -3622,7 +3622,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -3643,7 +3643,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -3688,7 +3688,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -3726,12 +3726,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -3750,9 +3750,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -3771,9 +3771,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -3792,9 +3792,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -3813,9 +3813,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -3834,9 +3834,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -3875,12 +3875,12 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); return new ManagedChain(newHeadPtr); } @@ -3905,13 +3905,13 @@ public ManagedChain(ManagedChain previous, T6 item6 Marshal.StructureToPtr(item6, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -3942,12 +3942,12 @@ public ManagedChain Truncate(out T6 item6) // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -4144,18 +4144,18 @@ public unsafe class ManagedChain : ManagedCh /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -4165,7 +4165,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -4186,7 +4186,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -4207,7 +4207,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -4228,7 +4228,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -4249,7 +4249,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -4270,7 +4270,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -4291,7 +4291,7 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. @@ -4337,7 +4337,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -4379,12 +4379,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -4403,9 +4403,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -4424,9 +4424,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -4445,9 +4445,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -4466,9 +4466,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -4487,9 +4487,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -4508,9 +4508,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item6, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item7Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T7 item7 = default; expectedStructureType = item7.StructureType(); @@ -4549,13 +4549,13 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); return new ManagedChain(newHeadPtr); } @@ -4580,14 +4580,14 @@ public ManagedChain(ManagedChain previous, T7 it Marshal.StructureToPtr(item7, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -4618,13 +4618,13 @@ public ManagedChain Truncate(out T7 item7) // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -4838,18 +4838,18 @@ public unsafe class ManagedChain : Manag /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -4859,7 +4859,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -4880,7 +4880,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -4901,7 +4901,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -4922,7 +4922,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -4943,7 +4943,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -4964,7 +4964,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -4985,7 +4985,7 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. @@ -5006,7 +5006,7 @@ public T7 Item7 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. @@ -5053,7 +5053,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -5099,12 +5099,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -5123,9 +5123,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -5144,9 +5144,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -5165,9 +5165,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -5186,9 +5186,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -5207,9 +5207,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -5228,9 +5228,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item6, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item7Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T7 item7 = default; expectedStructureType = item7.StructureType(); @@ -5249,9 +5249,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item7, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item8Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T8 item8 = default; expectedStructureType = item8.StructureType(); @@ -5290,14 +5290,14 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); return new ManagedChain(newHeadPtr); } @@ -5322,15 +5322,15 @@ public ManagedChain(ManagedChain previous, T Marshal.StructureToPtr(item8, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); - ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); + ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -5361,14 +5361,14 @@ public ManagedChain Truncate(out T8 item8) // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -5599,18 +5599,18 @@ public unsafe class ManagedChain : M /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -5620,7 +5620,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -5641,7 +5641,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -5662,7 +5662,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -5683,7 +5683,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -5704,7 +5704,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -5725,7 +5725,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -5746,7 +5746,7 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. @@ -5767,7 +5767,7 @@ public T7 Item7 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. @@ -5788,7 +5788,7 @@ public T8 Item8 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. @@ -5836,7 +5836,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -5886,12 +5886,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -5910,9 +5910,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -5931,9 +5931,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -5952,9 +5952,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -5973,9 +5973,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -5994,9 +5994,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -6015,9 +6015,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item6, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item7Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T7 item7 = default; expectedStructureType = item7.StructureType(); @@ -6036,9 +6036,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item7, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item8Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T8 item8 = default; expectedStructureType = item8.StructureType(); @@ -6057,9 +6057,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item8, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item9Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T9 item9 = default; expectedStructureType = item9.StructureType(); @@ -6098,15 +6098,15 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); return new ManagedChain(newHeadPtr); } @@ -6131,16 +6131,16 @@ public ManagedChain(ManagedChain previou Marshal.StructureToPtr(item9, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); - ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); - ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); + ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); + ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -6171,15 +6171,15 @@ public ManagedChain Truncate(out T9 item // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -6427,18 +6427,18 @@ public unsafe class ManagedChain /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -6448,7 +6448,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -6469,7 +6469,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -6490,7 +6490,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -6511,7 +6511,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -6532,7 +6532,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -6553,7 +6553,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -6574,7 +6574,7 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. @@ -6595,7 +6595,7 @@ public T7 Item7 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. @@ -6616,7 +6616,7 @@ public T8 Item8 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. @@ -6637,7 +6637,7 @@ public T9 Item9 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. @@ -6686,7 +6686,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -6740,12 +6740,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -6764,9 +6764,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -6785,9 +6785,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -6806,9 +6806,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -6827,9 +6827,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -6848,9 +6848,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -6869,9 +6869,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item6, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item7Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T7 item7 = default; expectedStructureType = item7.StructureType(); @@ -6890,9 +6890,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item7, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item8Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T8 item8 = default; expectedStructureType = item8.StructureType(); @@ -6911,9 +6911,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item8, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item9Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T9 item9 = default; expectedStructureType = item9.StructureType(); @@ -6932,9 +6932,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item9, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item10Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T10 item10 = default; expectedStructureType = item10.StructureType(); @@ -6973,16 +6973,16 @@ public ManagedChain Duplicate() // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); return new ManagedChain(newHeadPtr); } @@ -7007,17 +7007,17 @@ public ManagedChain(ManagedChain pre Marshal.StructureToPtr(item10, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); - ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); - ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); - ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); + ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); + ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); + ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -7048,16 +7048,16 @@ public ManagedChain Truncate(out T10 // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -7322,18 +7322,18 @@ public unsafe class ManagedChain /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -7343,7 +7343,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -7364,7 +7364,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -7385,7 +7385,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -7406,7 +7406,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -7427,7 +7427,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -7448,7 +7448,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -7469,7 +7469,7 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. @@ -7490,7 +7490,7 @@ public T7 Item7 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. @@ -7511,7 +7511,7 @@ public T8 Item8 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. @@ -7532,7 +7532,7 @@ public T9 Item9 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. @@ -7553,7 +7553,7 @@ public T10 Item10 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. @@ -7603,7 +7603,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -7661,12 +7661,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -7685,9 +7685,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -7706,9 +7706,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -7727,9 +7727,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -7748,9 +7748,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -7769,9 +7769,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -7790,9 +7790,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item6, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item7Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T7 item7 = default; expectedStructureType = item7.StructureType(); @@ -7811,9 +7811,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item7, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item8Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T8 item8 = default; expectedStructureType = item8.StructureType(); @@ -7832,9 +7832,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item8, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item9Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T9 item9 = default; expectedStructureType = item9.StructureType(); @@ -7853,9 +7853,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item9, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item10Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T10 item10 = default; expectedStructureType = item10.StructureType(); @@ -7874,9 +7874,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item10, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item11Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T11 item11 = default; expectedStructureType = item11.StructureType(); @@ -7915,17 +7915,17 @@ public ManagedChain Duplic // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); return new ManagedChain(newHeadPtr); } @@ -7950,18 +7950,18 @@ public ManagedChain(ManagedChainPNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); - ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); - ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); - ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); - ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); + ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); + ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); + ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); + ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -7992,17 +7992,17 @@ public ManagedChain Truncate(ou // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -8284,18 +8284,18 @@ public unsafe class ManagedChain /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -8305,7 +8305,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -8326,7 +8326,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -8347,7 +8347,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -8368,7 +8368,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -8389,7 +8389,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -8410,7 +8410,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -8431,7 +8431,7 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. @@ -8452,7 +8452,7 @@ public T7 Item7 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. @@ -8473,7 +8473,7 @@ public T8 Item8 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. @@ -8494,7 +8494,7 @@ public T9 Item9 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. @@ -8515,7 +8515,7 @@ public T10 Item10 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. @@ -8536,7 +8536,7 @@ public T11 Item11 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item12Ptr => (Chain*) (_headPtr + Item12Offset); + public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); /// /// Gets or sets item #12 in the chain. @@ -8587,7 +8587,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -8649,12 +8649,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -8673,9 +8673,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -8694,9 +8694,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -8715,9 +8715,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -8736,9 +8736,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -8757,9 +8757,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -8778,9 +8778,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item6, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item7Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T7 item7 = default; expectedStructureType = item7.StructureType(); @@ -8799,9 +8799,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item7, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item8Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T8 item8 = default; expectedStructureType = item8.StructureType(); @@ -8820,9 +8820,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item8, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item9Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T9 item9 = default; expectedStructureType = item9.StructureType(); @@ -8841,9 +8841,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item9, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item10Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T10 item10 = default; expectedStructureType = item10.StructureType(); @@ -8862,9 +8862,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item10, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item11Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T11 item11 = default; expectedStructureType = item11.StructureType(); @@ -8883,9 +8883,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item11, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item12Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item12Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T12 item12 = default; expectedStructureType = item12.StructureType(); @@ -8924,18 +8924,18 @@ public ManagedChain D // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); - ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); + ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); return new ManagedChain(newHeadPtr); } @@ -8960,19 +8960,19 @@ public ManagedChain(ManagedChainPNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); - ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); - ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); - ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); - ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); - ((Chain*)(_headPtr + Item11Offset))->PNext = (Chain*) (_headPtr + Item12Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); + ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); + ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); + ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); + ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); + ((BaseInStructure*)(_headPtr + Item11Offset))->PNext = (BaseInStructure*) (_headPtr + Item12Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -9003,18 +9003,18 @@ public ManagedChain Trunca // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); - ((Chain*)(newHeadPtr + Item11Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); + ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -9313,18 +9313,18 @@ public unsafe class ManagedChain /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -9334,7 +9334,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -9355,7 +9355,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -9376,7 +9376,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -9397,7 +9397,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -9418,7 +9418,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -9439,7 +9439,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -9460,7 +9460,7 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. @@ -9481,7 +9481,7 @@ public T7 Item7 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. @@ -9502,7 +9502,7 @@ public T8 Item8 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. @@ -9523,7 +9523,7 @@ public T9 Item9 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. @@ -9544,7 +9544,7 @@ public T10 Item10 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. @@ -9565,7 +9565,7 @@ public T11 Item11 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item12Ptr => (Chain*) (_headPtr + Item12Offset); + public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); /// /// Gets or sets item #12 in the chain. @@ -9586,7 +9586,7 @@ public T12 Item12 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item13Ptr => (Chain*) (_headPtr + Item13Offset); + public BaseInStructure* Item13Ptr => (BaseInStructure*) (_headPtr + Item13Offset); /// /// Gets or sets item #13 in the chain. @@ -9638,7 +9638,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -9704,12 +9704,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -9728,9 +9728,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -9749,9 +9749,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -9770,9 +9770,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -9791,9 +9791,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -9812,9 +9812,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -9833,9 +9833,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item6, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item7Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T7 item7 = default; expectedStructureType = item7.StructureType(); @@ -9854,9 +9854,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item7, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item8Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T8 item8 = default; expectedStructureType = item8.StructureType(); @@ -9875,9 +9875,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item8, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item9Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T9 item9 = default; expectedStructureType = item9.StructureType(); @@ -9896,9 +9896,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item9, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item10Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T10 item10 = default; expectedStructureType = item10.StructureType(); @@ -9917,9 +9917,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item10, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item11Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T11 item11 = default; expectedStructureType = item11.StructureType(); @@ -9938,9 +9938,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item11, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item12Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item12Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T12 item12 = default; expectedStructureType = item12.StructureType(); @@ -9959,9 +9959,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item12, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item13Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item13Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T13 item13 = default; expectedStructureType = item13.StructureType(); @@ -10000,19 +10000,19 @@ public ManagedChainPNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); - ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); - ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); + ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); + ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); return new ManagedChain(newHeadPtr); } @@ -10037,20 +10037,20 @@ public ManagedChain(ManagedChainPNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); - ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); - ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); - ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); - ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); - ((Chain*)(_headPtr + Item11Offset))->PNext = (Chain*) (_headPtr + Item12Offset); - ((Chain*)(_headPtr + Item12Offset))->PNext = (Chain*) (_headPtr + Item13Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); + ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); + ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); + ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); + ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); + ((BaseInStructure*)(_headPtr + Item11Offset))->PNext = (BaseInStructure*) (_headPtr + Item12Offset); + ((BaseInStructure*)(_headPtr + Item12Offset))->PNext = (BaseInStructure*) (_headPtr + Item13Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -10081,19 +10081,19 @@ public ManagedChain T // Block copy original struct data for speed Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); - ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); - ((Chain*)(newHeadPtr + Item12Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); + ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); + ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -10409,18 +10409,18 @@ public unsafe class ManagedChain /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -10430,7 +10430,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -10451,7 +10451,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -10472,7 +10472,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -10493,7 +10493,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -10514,7 +10514,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -10535,7 +10535,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -10556,7 +10556,7 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. @@ -10577,7 +10577,7 @@ public T7 Item7 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. @@ -10598,7 +10598,7 @@ public T8 Item8 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. @@ -10619,7 +10619,7 @@ public T9 Item9 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. @@ -10640,7 +10640,7 @@ public T10 Item10 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. @@ -10661,7 +10661,7 @@ public T11 Item11 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item12Ptr => (Chain*) (_headPtr + Item12Offset); + public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); /// /// Gets or sets item #12 in the chain. @@ -10682,7 +10682,7 @@ public T12 Item12 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item13Ptr => (Chain*) (_headPtr + Item13Offset); + public BaseInStructure* Item13Ptr => (BaseInStructure*) (_headPtr + Item13Offset); /// /// Gets or sets item #13 in the chain. @@ -10703,7 +10703,7 @@ public T13 Item13 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item14Ptr => (Chain*) (_headPtr + Item14Offset); + public BaseInStructure* Item14Ptr => (BaseInStructure*) (_headPtr + Item14Offset); /// /// Gets or sets item #14 in the chain. @@ -10756,7 +10756,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -10826,12 +10826,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -10850,9 +10850,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -10871,9 +10871,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -10892,9 +10892,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -10913,9 +10913,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -10934,9 +10934,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -10955,9 +10955,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item6, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item7Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T7 item7 = default; expectedStructureType = item7.StructureType(); @@ -10976,9 +10976,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item7, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item8Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T8 item8 = default; expectedStructureType = item8.StructureType(); @@ -10997,9 +10997,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item8, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item9Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T9 item9 = default; expectedStructureType = item9.StructureType(); @@ -11018,9 +11018,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item9, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item10Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T10 item10 = default; expectedStructureType = item10.StructureType(); @@ -11039,9 +11039,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item10, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item11Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T11 item11 = default; expectedStructureType = item11.StructureType(); @@ -11060,9 +11060,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item11, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item12Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item12Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T12 item12 = default; expectedStructureType = item12.StructureType(); @@ -11081,9 +11081,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item12, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item13Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item13Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T13 item13 = default; expectedStructureType = item13.StructureType(); @@ -11102,9 +11102,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item13, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item14Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item14Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T14 item14 = default; expectedStructureType = item14.StructureType(); @@ -11143,20 +11143,20 @@ public ManagedChainPNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); - ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); - ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); - ((Chain*)(newHeadPtr + Item13Offset))->PNext = (Chain*) (newHeadPtr + Item14Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); + ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); + ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); + ((BaseInStructure*)(newHeadPtr + Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item14Offset); return new ManagedChain(newHeadPtr); } @@ -11181,21 +11181,21 @@ public ManagedChain(ManagedChainPNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); - ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); - ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); - ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); - ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); - ((Chain*)(_headPtr + Item11Offset))->PNext = (Chain*) (_headPtr + Item12Offset); - ((Chain*)(_headPtr + Item12Offset))->PNext = (Chain*) (_headPtr + Item13Offset); - ((Chain*)(_headPtr + Item13Offset))->PNext = (Chain*) (_headPtr + Item14Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); + ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); + ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); + ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); + ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); + ((BaseInStructure*)(_headPtr + Item11Offset))->PNext = (BaseInStructure*) (_headPtr + Item12Offset); + ((BaseInStructure*)(_headPtr + Item12Offset))->PNext = (BaseInStructure*) (_headPtr + Item13Offset); + ((BaseInStructure*)(_headPtr + Item13Offset))->PNext = (BaseInStructure*) (_headPtr + Item14Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -11226,20 +11226,20 @@ public ManagedChainPNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); - ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); - ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); - ((Chain*)(newHeadPtr + Item13Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); + ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); + ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); + ((BaseInStructure*)(newHeadPtr + Item13Offset))->PNext = null; return new ManagedChain(newHeadPtr); } @@ -11572,18 +11572,18 @@ public unsafe class ManagedChain /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -11593,7 +11593,7 @@ public TChain Head /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -11614,7 +11614,7 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item2Ptr => (Chain*) (_headPtr + Item2Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// /// Gets or sets item #2 in the chain. @@ -11635,7 +11635,7 @@ public T2 Item2 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item3Ptr => (Chain*) (_headPtr + Item3Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// /// Gets or sets item #3 in the chain. @@ -11656,7 +11656,7 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item4Ptr => (Chain*) (_headPtr + Item4Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// /// Gets or sets item #4 in the chain. @@ -11677,7 +11677,7 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item5Ptr => (Chain*) (_headPtr + Item5Offset); + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// /// Gets or sets item #5 in the chain. @@ -11698,7 +11698,7 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item6Ptr => (Chain*) (_headPtr + Item6Offset); + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// /// Gets or sets item #6 in the chain. @@ -11719,7 +11719,7 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item7Ptr => (Chain*) (_headPtr + Item7Offset); + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// /// Gets or sets item #7 in the chain. @@ -11740,7 +11740,7 @@ public T7 Item7 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item8Ptr => (Chain*) (_headPtr + Item8Offset); + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); /// /// Gets or sets item #8 in the chain. @@ -11761,7 +11761,7 @@ public T8 Item8 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item9Ptr => (Chain*) (_headPtr + Item9Offset); + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); /// /// Gets or sets item #9 in the chain. @@ -11782,7 +11782,7 @@ public T9 Item9 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item10Ptr => (Chain*) (_headPtr + Item10Offset); + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); /// /// Gets or sets item #10 in the chain. @@ -11803,7 +11803,7 @@ public T10 Item10 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item11Ptr => (Chain*) (_headPtr + Item11Offset); + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); /// /// Gets or sets item #11 in the chain. @@ -11824,7 +11824,7 @@ public T11 Item11 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item12Ptr => (Chain*) (_headPtr + Item12Offset); + public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); /// /// Gets or sets item #12 in the chain. @@ -11845,7 +11845,7 @@ public T12 Item12 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item13Ptr => (Chain*) (_headPtr + Item13Offset); + public BaseInStructure* Item13Ptr => (BaseInStructure*) (_headPtr + Item13Offset); /// /// Gets or sets item #13 in the chain. @@ -11866,7 +11866,7 @@ public T13 Item13 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item14Ptr => (Chain*) (_headPtr + Item14Offset); + public BaseInStructure* Item14Ptr => (BaseInStructure*) (_headPtr + Item14Offset); /// /// Gets or sets item #14 in the chain. @@ -11887,7 +11887,7 @@ public T14 Item14 /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item15Ptr => (Chain*) (_headPtr + Item15Offset); + public BaseInStructure* Item15Ptr => (BaseInStructure*) (_headPtr + Item15Offset); /// /// Gets or sets item #15 in the chain. @@ -11941,7 +11941,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + BaseInStructure* itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -12015,12 +12015,12 @@ public ManagedChain(out string errors, TChain chain) chain.StructureType(); Marshal.StructureToPtr(chain, _headPtr, false); StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); @@ -12039,9 +12039,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item2Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); @@ -12060,9 +12060,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item3Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); @@ -12081,9 +12081,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item4Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T4 item4 = default; expectedStructureType = item4.StructureType(); @@ -12102,9 +12102,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item4, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item5Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T5 item5 = default; expectedStructureType = item5.StructureType(); @@ -12123,9 +12123,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item5, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item6Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T6 item6 = default; expectedStructureType = item6.StructureType(); @@ -12144,9 +12144,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item6, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item7Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T7 item7 = default; expectedStructureType = item7.StructureType(); @@ -12165,9 +12165,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item7, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item8Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T8 item8 = default; expectedStructureType = item8.StructureType(); @@ -12186,9 +12186,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item8, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item9Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T9 item9 = default; expectedStructureType = item9.StructureType(); @@ -12207,9 +12207,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item9, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item10Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T10 item10 = default; expectedStructureType = item10.StructureType(); @@ -12228,9 +12228,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item10, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item11Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T11 item11 = default; expectedStructureType = item11.StructureType(); @@ -12249,9 +12249,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item11, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item12Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item12Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T12 item12 = default; expectedStructureType = item12.StructureType(); @@ -12270,9 +12270,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item12, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item13Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item13Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T13 item13 = default; expectedStructureType = item13.StructureType(); @@ -12291,9 +12291,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item13, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item14Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item14Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T14 item14 = default; expectedStructureType = item14.StructureType(); @@ -12312,9 +12312,9 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item14, (nint) newPtr, false); - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item15Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item15Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T15 item15 = default; expectedStructureType = item15.StructureType(); @@ -12353,21 +12353,21 @@ public ManagedChainPNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); - ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); - ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); - ((Chain*)(newHeadPtr + Item13Offset))->PNext = (Chain*) (newHeadPtr + Item14Offset); - ((Chain*)(newHeadPtr + Item14Offset))->PNext = (Chain*) (newHeadPtr + Item15Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); + ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); + ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); + ((BaseInStructure*)(newHeadPtr + Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item14Offset); + ((BaseInStructure*)(newHeadPtr + Item14Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item15Offset); return new ManagedChain(newHeadPtr); } @@ -12392,22 +12392,22 @@ public ManagedChain(ManagedChainPNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + Item1Offset))->PNext = (Chain*) (_headPtr + Item2Offset); - ((Chain*)(_headPtr + Item2Offset))->PNext = (Chain*) (_headPtr + Item3Offset); - ((Chain*)(_headPtr + Item3Offset))->PNext = (Chain*) (_headPtr + Item4Offset); - ((Chain*)(_headPtr + Item4Offset))->PNext = (Chain*) (_headPtr + Item5Offset); - ((Chain*)(_headPtr + Item5Offset))->PNext = (Chain*) (_headPtr + Item6Offset); - ((Chain*)(_headPtr + Item6Offset))->PNext = (Chain*) (_headPtr + Item7Offset); - ((Chain*)(_headPtr + Item7Offset))->PNext = (Chain*) (_headPtr + Item8Offset); - ((Chain*)(_headPtr + Item8Offset))->PNext = (Chain*) (_headPtr + Item9Offset); - ((Chain*)(_headPtr + Item9Offset))->PNext = (Chain*) (_headPtr + Item10Offset); - ((Chain*)(_headPtr + Item10Offset))->PNext = (Chain*) (_headPtr + Item11Offset); - ((Chain*)(_headPtr + Item11Offset))->PNext = (Chain*) (_headPtr + Item12Offset); - ((Chain*)(_headPtr + Item12Offset))->PNext = (Chain*) (_headPtr + Item13Offset); - ((Chain*)(_headPtr + Item13Offset))->PNext = (Chain*) (_headPtr + Item14Offset); - ((Chain*)(_headPtr + Item14Offset))->PNext = (Chain*) (_headPtr + Item15Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); + ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); + ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); + ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); + ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); + ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); + ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); + ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); + ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); + ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); + ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); + ((BaseInStructure*)(_headPtr + Item11Offset))->PNext = (BaseInStructure*) (_headPtr + Item12Offset); + ((BaseInStructure*)(_headPtr + Item12Offset))->PNext = (BaseInStructure*) (_headPtr + Item13Offset); + ((BaseInStructure*)(_headPtr + Item13Offset))->PNext = (BaseInStructure*) (_headPtr + Item14Offset); + ((BaseInStructure*)(_headPtr + Item14Offset))->PNext = (BaseInStructure*) (_headPtr + Item15Offset); + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -12438,21 +12438,21 @@ public ManagedChainPNext = (Chain*) (newHeadPtr + Item1Offset); - ((Chain*)(newHeadPtr + Item1Offset))->PNext = (Chain*) (newHeadPtr + Item2Offset); - ((Chain*)(newHeadPtr + Item2Offset))->PNext = (Chain*) (newHeadPtr + Item3Offset); - ((Chain*)(newHeadPtr + Item3Offset))->PNext = (Chain*) (newHeadPtr + Item4Offset); - ((Chain*)(newHeadPtr + Item4Offset))->PNext = (Chain*) (newHeadPtr + Item5Offset); - ((Chain*)(newHeadPtr + Item5Offset))->PNext = (Chain*) (newHeadPtr + Item6Offset); - ((Chain*)(newHeadPtr + Item6Offset))->PNext = (Chain*) (newHeadPtr + Item7Offset); - ((Chain*)(newHeadPtr + Item7Offset))->PNext = (Chain*) (newHeadPtr + Item8Offset); - ((Chain*)(newHeadPtr + Item8Offset))->PNext = (Chain*) (newHeadPtr + Item9Offset); - ((Chain*)(newHeadPtr + Item9Offset))->PNext = (Chain*) (newHeadPtr + Item10Offset); - ((Chain*)(newHeadPtr + Item10Offset))->PNext = (Chain*) (newHeadPtr + Item11Offset); - ((Chain*)(newHeadPtr + Item11Offset))->PNext = (Chain*) (newHeadPtr + Item12Offset); - ((Chain*)(newHeadPtr + Item12Offset))->PNext = (Chain*) (newHeadPtr + Item13Offset); - ((Chain*)(newHeadPtr + Item13Offset))->PNext = (Chain*) (newHeadPtr + Item14Offset); - ((Chain*)(newHeadPtr + Item14Offset))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); + ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); + ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); + ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); + ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); + ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); + ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); + ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); + ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); + ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); + ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); + ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); + ((BaseInStructure*)(newHeadPtr + Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item14Offset); + ((BaseInStructure*)(newHeadPtr + Item14Offset))->PNext = null; return new ManagedChain(newHeadPtr); } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt index 42f5120923..7b072af330 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt @@ -213,18 +213,18 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain /// /// Gets a pointer to the current head. /// - public Chain* HeadPtr => (Chain*) _headPtr; + public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -238,7 +238,7 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item<#= j #>Ptr => (Chain*) (_headPtr + Item<#= j #>Offset); + public BaseInStructure* Item<#= j #>Ptr => (BaseInStructure*) (_headPtr + Item<#= j #>Offset); /// /// Gets or sets item #<#= j #> in the chain. @@ -284,7 +284,7 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain for (var j = 1; j < i; j++) { #> - <#= j == 1 ? "Chain* " : "" #>itemPtr = Item<#= j #>Ptr; + <#= j == 1 ? "BaseInStructure* " : "" #>itemPtr = Item<#= j #>Ptr; item<#= j #>.StructureType(); Marshal.StructureToPtr(item<#= j #>, (nint)itemPtr, false); <#= j == 1 ? "HeadPtr" : $"Item{j - 1}Ptr" #>->PNext = itemPtr; @@ -315,16 +315,16 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain { #> StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) _headPtr; <# for (var j = 1; j < i; j++) { #> - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item<#= j #>Offset); - newPtr = newPtr->PNext; + existingPtr = (BaseInStructure*)existingPtr->PNext; + newPtr->PNext = (BaseInStructure*)(_headPtr + Item<#= j #>Offset); + newPtr = (BaseInStructure*)newPtr->PNext; T<#= j #> item<#= j #> = default; <#= j == 1 ? "var " : "" #>expectedStructureType = item<#= j #>.StructureType(); @@ -380,7 +380,7 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain { #> // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); <# } // if (i > 1) #> @@ -388,7 +388,7 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain for (var j = 2; j < i; j++) { #> - ((Chain*)(newHeadPtr + Item<#= j - 1 #>Offset))->PNext = (Chain*) (newHeadPtr + Item<#= j #>Offset); + ((BaseInStructure*)(newHeadPtr + Item<#= j - 1 #>Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item<#= j #>Offset); <# } // for (int j = 1; j < i; j++) { #> @@ -421,16 +421,16 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain Marshal.StructureToPtr(item<#= i - 1 #>, _headPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); + ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); <# for (var j = 2; j < i; j++) { #> - ((Chain*)(_headPtr + Item<#= j - 1 #>Offset))->PNext = (Chain*) (_headPtr + Item<#= j #>Offset); + ((BaseInStructure*)(_headPtr + Item<#= j - 1 #>Offset))->PNext = (BaseInStructure*) (_headPtr + Item<#= j #>Offset); <# } // for (int j = 1; j < i; j++) { #> - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; } /// @@ -465,19 +465,19 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain if (i > 2) { #> - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); <# for (var j = 2; j < i; j++) { #> - ((Chain*)(newHeadPtr + Item<#= j - 1 #>Offset))->PNext = <#= j == i -1 ? "null" : $"(Chain*) (newHeadPtr + Item{j}Offset)"#>; + ((BaseInStructure*)(newHeadPtr + Item<#= j - 1 #>Offset))->PNext = <#= j == i -1 ? "null" : $"(BaseInStructure*) (newHeadPtr + Item{j}Offset)"#>; <# } // for (int j = 1; j < i - 1; j++) } else // if (i > 1) { #> - ((Chain*)newHeadPtr)->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = null; <# } #> diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs index 30cec6947a..c642f30156 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs @@ -40,9 +40,9 @@ StructureType IStructuredType.StructureType() } /// - unsafe Chain* IChainable.PNext + unsafe BaseInStructure* IChainable.PNext { - get => (Chain*) PNext; + get => (BaseInStructure*) PNext; set => PNext = value; } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs index 9e9bf8ac5d..f370c44dc0 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs @@ -40,9 +40,9 @@ StructureType IStructuredType.StructureType() } /// - unsafe Chain* IChainable.PNext + unsafe BaseInStructure* IChainable.PNext { - get => (Chain*) PNext; + get => (BaseInStructure*) PNext; set => PNext = value; } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs index 9b12590611..0f3bc822ff 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs @@ -44,9 +44,9 @@ StructureType IStructuredType.StructureType() } /// - unsafe Chain* IChainable.PNext + unsafe BaseInStructure* IChainable.PNext { - get => (Chain*) PNext; + get => (BaseInStructure*) PNext; set => PNext = value; } From 8152c47559316c306aa2ac30702f2a0f72b96fe1 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Wed, 10 Nov 2021 01:01:11 +0000 Subject: [PATCH 31/34] docs: Updated the first two proposals Added details about PRs and the new `Any` extension methods. --- ... Chaining - #1 StructureType correction.md | 4 +- ...Struct Chaining - #2 Unmanaged Chaining.md | 313 +++++++++++++++--- 2 files changed, 267 insertions(+), 50 deletions(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md index 0af0ccad20..092e78bbf5 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #1 StructureType correction.md @@ -8,6 +8,8 @@ This is a tiny pre-requisite for and is of limited value otherwise. Its primary purpose is to mark any structure that requires it's `SType` field to be correctly set when passing to Vulkan, and to provide a mechanism for doing so. +A full implementation can be found [in Pull Request 680](https://github.com/dotnet/Silk.NET/pull/680). + # Contributors - [Craig Dean, DevDecoder](https://github.com/thargy) @@ -17,7 +19,7 @@ correctly set when passing to Vulkan, and to provide a mechanism for doing so. - [x] Proposed - [ ] Discussed with API Review Board (ARB) - [ ] Approved -- [ ] Implemented +- [x] Implemented # Design Decisions diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md index 8b179e185c..983c501d2b 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md @@ -6,7 +6,7 @@ on [Proposal - Vulkan Struct Chaining - #1 StructureType correction](Proposal%20 This proposal presents a lightweight mechanism for fluently building Vulkan Structure Chains. You may wish to start with the [Usage section below](#Usage) to aid understanding. There is also a fully working prototype -[in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/). +[in Pull Request 683](https://github.com/dotnet/Silk.NET/pull/683). To do so it marks any structure that meets the following requirements as being `IChainable`: @@ -22,19 +22,22 @@ is triggerred for the structure, providing a mechanism for ensuring the `SType` a `BaseInStructure* PNext { get; set; }` property for easy access to the next item in the chain. The presence of the `IChainable` interface, also acts as a **guarantee** that it is safe to cast any pointer of a struct -implementing it to a pointer to a `BaseInStructure` struct, which is a struct which has just the `SType` and `PNext` fields -present. Therefore it is always possible to cast `void* PNext` of an `IChainable` struct to `BaseInStructure*`. It is this -guarantee that requires the position of the fields to be fixed (which they are in practice). However, by ensuring we -validate the constraints at build time (when choosing to add the interface), we can prevent downstream bugs occurring at -run time. +implementing it to a pointer to a `BaseInStructure` struct, which is a struct which has just the `SType` and `PNext` +fields present. Therefore it is always possible to cast `void* PNext` of an `IChainable` struct to `BaseInStructure*`. +It is this guarantee that requires the position of the fields to be fixed (which they are in practice). However, by +ensuring we validate the constraints at build time (when choosing to add the interface), we can prevent downstream bugs +occurring at run time. **Note** that the `IChainable` interface adds the additional constraint that the `StructureType SType` field must be at -offset 0, i.e. in the first position. +offset 0, i.e. in the first position to facilitate this functionality - which is not a constraint of `IStructuredType`. -However, rather than extending `IChainable` directly, it will be more common to choose one of `IChainStart` -or `IExtendsChain` (both of which extend `IChainable`). `BuildTools` will do this based on the `structextends` -attribute provided in -the [Vulkan Specification](https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/registry/vk.xml)). +However, rather than extending `IChainable` directly, where +the [Vulkan Specification](https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/registry/vk.xml)) +specifies chaining constraints, via the presence of the `structextends` attribute, `BuildTools` chooses one +of `IChainStart` or `IExtendsChain` (both of which extend `IChainable`). The specification has nearly 100 chains +defined in this manner, and many of the >700 structures form part of these chains. However, over 200 structures are not +curretnly defined as part of a chain, and as such, all the utilities proposed have a 'looser' mechanism for working +with `IChainable` directly when it is necessary to do so. For example, if `struct B` extends `struct A`, then `struct B` will be marked with `IExtendsChain` and `struct A` will be marked with `IChainStart`. A struct may only extend `IChainStart` once (even though it may appear in @@ -67,24 +70,37 @@ public static unsafe ref TChain SetNext(this ref TChain chain, re where TChain : struct, IChainStart where TNext : struct, IExtendsChain {...} +public static unsafe ref TChain SetNextAny(this ref TChain chain, ref TNext value, + where TChain : struct, IChainable + where TNext : struct, IChainable {...} + public static unsafe ref TChain AddNext(this ref TChain chain, out TNext next) where TChain : struct, IChainStart where TNext : struct, IExtendsChain {...} + +public static unsafe ref TChain AddNextAny(this ref TChain chain, out TNext next) + where TChain : struct, IChainable + where TNext : struct, IChainable {...} public static unsafe ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) where TChain : struct, IChainStart where TNext : struct, IExtendsChain {...} +public static unsafe ref TChain TryAddNextAny(this ref TChain chain, out TNext next, out bool added) + where TChain : struct, IChainable + where TNext : struct, IChainable {...} + public static unsafe int IndexOf(this ref TChain chain, ref TNext value) where TChain : struct, IChainStart where TNext : struct, IExtendsChain {...} -``` -Their implementation can be -found [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs) and -their use is detailed below. +public static unsafe int IndexOfAny(this ref TChain chain, ref TNext value) + where TChain : struct, IChainable + where TNext : struct, IChainable {...} +``` -These extension methods +An implementation can be found [in Pull Request 683](https://github.com/dotnet/Silk.NET/pull/683) and their use is +detailed below. # Contributors @@ -95,7 +111,7 @@ These extension methods - [x] Proposed - [ ] Discussed with API Review Board (ARB) - [ ] Approved -- [ ] Implemented +- [x] Implemented # Design Decisions @@ -129,12 +145,20 @@ To be discussed: # Usage -The proposal provides for the following usage patterns: +The proposal provides for the following usages. Note that where an `Any` extension method is mentioned, it is identical +to the non-`Any` version (e.g. `AddNext` and `AddNextAny` are equivalent), save that the `Any` version does not +constrain the types to those associated with a defined chain. ### Chain Building -You can happily create the start of a chain as usual, and it's `SType` will be coerced when you start using it as a -chain: +You can happily create the start of a chain as usual, by declaring a variable first. Indeed it is necessary to do so if +you wish to specify non-default values (though you can also make use of `SetNext`s replace functionality). You also need +to use this approach when starting a chain which is not explicitly defined as a chain start by the specification. If you +do start a chain with such a structure, you will have to use the `Any` versions of the extension methods below to +continue manipulating it. + +Regardless, the `SType` and `PNext` will be overwritten whenever you start manipulating the chain, so you should never +set them manually. For example: ```csharp var createInfo = new DeviceCreateInfo @@ -145,7 +169,7 @@ var createInfo = new DeviceCreateInfo createinfo.AddNext... ``` --in many cases, we only want to create a default structure for population by the API. To do so, we use the +In many cases, we only want to create a default structure for population by the API. To do so, we use the static `BaseInStructure` method like so: ```csharp @@ -158,10 +182,10 @@ This has several advantages: - The structure's `SType` will be correctly set immediately. - The syntax is fluent, and creates more readable code when used with the other chaining methods (see below). -**Note** All the chaining methods return the current start of the chain by reference (including `BaseInStructure`). This allows -each method to scan the entire chain. More importantly, it allows the Type constraints to be checked during compile time -to ensure that a type actually extends the chain. One side effect is that `ref Chain(out)` outputs the newly created -chain _and_ returns a reference to it. This can cause confusion to less experienced C# devs, for example: +**Note** All the chaining methods return the current start of the chain by reference (including `BaseInStructure`). This +allows each method to scan the entire chain. More importantly, it allows the Type constraints to be checked during +compile time to ensure that a type actually can extend the chain. One side effect is that `ref Chain(out)` outputs the +newly created chain _and_ returns a reference to it. This can cause confusion to less experienced C# devs, for example: ```csharp // Don't do this, it is harmless but unnecessary and confusing! @@ -177,7 +201,12 @@ actually updates the `PNext` of variable `b`. Once the chain is built the final into `a`. None of this is undefined behaviour, but as it is generally poorly understood so none of the examples ever recommend assigning the output of a chain. -### AddNext +The `Chain` method is a static method implemented on `IChainStart` structures, the remaining methods are actually +extension methods. The methods ending with `Any` can be used with any `IChainable` structure, but they do not constrain +the entries, or the head of the chain to being structures explicitly mentioned by the specification. The non-`Any` +methods are more restrictive, and should usually be used in preference. + +### AddNext / AddNextAny The most common use case is to add an empty structure to the end of a chain for it to be populated by the Vulkan API, this can now be done like so: @@ -194,7 +223,7 @@ PhysicalDeviceFeatures2 Each method `out` puts a struct into the local stack frame for querying once populated, and the pointers point to this local variable. Despite generics and interfaces being used, the chain methods avoid the heap entirely. -### TryAddNext +### TryAddNext / TryAddNextAny You may only want to add a structure if it doesn't already exist in the chain, this can be done with `TryAddNext`, e.g.: @@ -207,7 +236,7 @@ PhysicalDeviceFeatures2 .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures2, out bool added); ``` -### SetNext +### SetNext / SetNextAny Sometimes we may wish to set the initial state of a structure, or replace any existing item within the structure that has the same `StructureType` we can do this with `SetNext`: @@ -255,7 +284,7 @@ PhysicalDeviceFeatures2 .SetNext(ref indexingFeatures2, true); ``` -### IndexOf +### IndexOf / IndexOfAny Sometimes it's useful to know if a structure you previously supplied is still in a chain, this can be done with `IndexOf`, which returns a non-negative index (zero-indexed) if the structure is found, eg.: @@ -297,6 +326,10 @@ namespace Silk.Net.Vulkan; /// to a pointer to a . public interface IChainable : IStructuredType { + /// + /// Points to the next in this chain, if any; otherwise . + /// + unsafe BaseInStructure* PNext { get; set; } } ``` @@ -336,14 +369,17 @@ public interface IExtendsChain : IChainable } ``` -### Chain Extensions +### Chain Extension Methods Provides the struct chaining functionality, the full implementation can be found [in the labs](../../src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ChainExtensions.cs): ```csharp -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; +/// +/// Extension methods and utilities for building unmanaged structure chains. +/// public static class Chain { /// @@ -364,21 +400,81 @@ public static class Chain /// { /// ShaderInputAttachmentArrayDynamicIndexing = true /// }; - /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKHR + /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKhr /// { /// AccelerationStructure = true /// }; /// /// PhysicalDeviceFeatures2 - /// .Chain(out var features2) + /// .BaseInStructure(out var features2) /// .SetNext(ref indexingFeatures) /// .SetNext(ref accelerationStructureFeaturesKhr); /// /// - public static unsafe ref TChain SetNext(this ref TChain chain, ref TNext value, - bool alwaysAdd = false) + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref TChain SetNext + ( + this ref TChain chain, + ref TNext value, + bool alwaysAdd = false + ) where TChain : struct, IChainStart - where TNext : struct, IExtendsChain {...} + where TNext : struct, IExtendsChain + => ref SetNextAny(ref chain, ref value, alwaysAdd); + + /// + /// Replaces a structure in the chain (if present, and is false), or adds it to the end. + /// + /// The current chain + /// A reference to the structure to update + /// Always adds to the end of the chain, even if an equivalent structure is present. + /// The type of the current chain + /// The type of the value + /// A reference to the value value in the chain + /// + /// Note that both the supplied chain, and the supplied value will have their `SType` correctly set. Further, + /// the supplied structure's will be overwritten. + /// To use + /// + /// var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + /// { + /// ShaderInputAttachmentArrayDynamicIndexing = true + /// }; + /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKhr + /// { + /// AccelerationStructure = true + /// }; + /// + /// PhysicalDeviceFeatures2 + /// .BaseInStructure(out var features2) + /// .SetNext(ref indexingFeatures) + /// .SetNext(ref accelerationStructureFeaturesKhr); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static unsafe ref TChain SetNextAny + ( + this ref TChain chain, + ref TNext value, + bool alwaysAdd = false + ) + where TChain : struct, IChainable + where TNext : struct, IChainable + {...} /// /// Adds a structure to the end of the chain. @@ -393,16 +489,60 @@ public static class Chain /// To use specify the output type required, e.g.: /// /// PhysicalDeviceFeatures2 - /// .Chain(out var features2) + /// .BaseInStructure(out var features2) /// .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) - /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeaturesKhr); + /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); /// /// Note, the value is always added, even if an equivalent value is added in the chain already. Use /// to only add if not already present. /// - public static unsafe ref TChain AddNext(this ref TChain chain, out TNext next) + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref TChain AddNext(this ref TChain chain, out TNext next) where TChain : struct, IChainStart - where TNext : struct, IExtendsChain {...} + where TNext : struct, IExtendsChain + => ref AddNextAny(ref chain, out next); + + /// + /// Adds a structure to the end of the chain. + /// + /// The current chain + /// The structure added to the end of the chain + /// The type of the current chain + /// The type of the structure to add + /// The reference to the chain. + /// + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .BaseInStructure(out var features2) + /// .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); + /// + /// Note, the value is always added, even if an equivalent value is added in the chain already. Use + /// to only add if not already present. + /// + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + /// + /// + /// + public static unsafe ref TChain AddNextAny(this ref TChain chain, out TNext next) + where TChain : struct, IChainable + where TNext : struct, IChainable + {...} /// /// Tries to add a structure to the end of the chain. @@ -418,13 +558,55 @@ public static class Chain /// To use specify the output type required, e.g.: /// /// PhysicalDeviceFeatures2 - /// .Chain(out var features2) + /// .BaseInStructure(out var features2) /// .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures, out var added); /// /// - public static unsafe ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) where TChain : struct, IChainStart - where TNext : struct, IExtendsChain {...} + where TNext : struct, IExtendsChain + => ref TryAddNextAny(ref chain, out next, out added); + + /// + /// Tries to add a structure to the end of the chain. + /// + /// The current chain + /// The structure added to the end of the chain + /// Whether the structure was actually added + /// The type of the current chain + /// The type of the structure to add + /// The reference to the chain. + /// + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .BaseInStructure(out var features2) + /// .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures, out var added); + /// + /// + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + /// + /// + /// + public static unsafe ref TChain TryAddNextAny(this ref TChain chain, out TNext next, out bool added) + where TChain : struct, IChainable + where TNext : struct, IChainable + {...} /// /// Returns the index of the in the , if present. @@ -434,18 +616,51 @@ public static class Chain /// The type of the current chain /// The type of the value /// The zero-indexed index if found; otherwise -1. - public static unsafe int IndexOf(this ref TChain chain, ref TNext value) + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOf(this ref TChain chain, ref TNext value) where TChain : struct, IChainStart - where TNext : struct, IExtendsChain {...} + where TNext : struct, IExtendsChain + => IndexOfAny(ref chain, ref value); + + /// + /// Returns the index of the in the , if present. + /// + /// The chain + /// The structure value + /// The type of the current chain + /// The type of the value + /// The zero-indexed index if found; otherwise -1. + /// + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + /// + /// + /// + public static unsafe int IndexOfAny(this ref TChain chain, ref TNext value) + where TChain : struct, IChainable + where TNext : struct, IChainable + {...} } ``` ### Chain Structure -The `BaseInStructure` struct makes it easy to access the `SType` and `PNext` of a structure pointed to by `void* PNext`, although -it is used internally, it is useful for consumers of Silk.Net to have access to use in their own scenarios, that is -because the `IChainable` interface does not directly expose the underlying `SType` and `PNext` fields; as they are -fields (not properties), and this proposal aims to avoid boxing (so we try not to use the interface directly +The `BaseInStructure` struct makes it easy to access the `SType` and `PNext` of a structure pointed to by `void* PNext`, +although it is used internally, it is useful for consumers of Silk.Net to have access to use in their own scenarios, +that is because the `IChainable` interface does not directly expose the underlying `SType` and `PNext` fields; as they +are fields (not properties), and this proposal aims to avoid boxing (so we try not to use the interface directly unnecessarily). ```csharp From a83156e9178f1112c79fb148d398be391ee6c5c4 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Thu, 11 Nov 2021 04:13:33 +0000 Subject: [PATCH 32/34] feat: Added `Any` functionality to `ManagedChain` * Removed instance methods and converted into static extension methods. * Added `Any` equivalents with looser constraints. * Various fixes to make prototype match more closely with current draft implementations, and `Silk.NET.Vulkan`. * Added tests. * Added efficient equality overloads. * Added ToString(). * Expose the `HeadPtr` and `Size` in the base class. --- ...n Struct Chaining - #3 Managed Chaining.md | 2 +- .../TestChainMetadata.cs | 2 +- .../TestChains.cs | 2 +- .../TestChainsAny.cs | 30 + .../TestCompilation.cs | 17 +- .../TestManagedChains.cs | 55 +- .../TestManagedChainsAny.cs | 193 + .../BaseInStructure.cs | 4 +- .../PrototypeStructChaining/Buffer.cs | 12 + .../PrototypeStructChaining/Chain.cs | 251 +- .../DeviceCreateInfo.cs | 2 +- .../PrototypeStructChaining/IChainStart.cs | 2 +- .../PrototypeStructChaining/IChainable.cs | 2 +- .../PrototypeStructChaining/IExtendsChain.cs | 2 +- .../IStructuredType.cs | 2 +- .../ManagedChain.gen.cs | 23211 ++++++++++------ .../ManagedChain.gen.tt | 702 +- ...lDeviceAccelerationStructureFeaturesKhr.cs | 2 +- ...hysicalDeviceDescriptorIndexingFeatures.cs | 2 +- .../PhysicalDeviceFeatures.cs | 2 +- .../PhysicalDeviceFeatures2.cs | 2 +- .../PrototypeStructChaining.csproj | 3 +- .../PrototypeStructChaining/StructureType.cs | 2 +- 23 files changed, 15930 insertions(+), 8574 deletions(-) create mode 100644 src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainsAny.cs create mode 100644 src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChainsAny.cs create mode 100644 src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Buffer.cs diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md index 47c6bbfc89..86f6456027 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md @@ -17,7 +17,7 @@ performance. However, many consumers are uncomfortable with pointers, and are especially prone to introducing bugs when placing structs onto the heap. This proposal provides a convenient `ManagedChain` class, and multiple -descendent `ManagedChain` classes to safely fix the structures in memory and prevent pointer bugs. +descendent `ManagedChain` (similar to the `System.Tuple` classes) classes to safely fix the structures in memory and prevent pointer bugs. Whenever a structure is loaded into the `ManagedChain` its `SType` and `PNext` are forced to be correct, preventing errors. Structures can be replaced at any time, and will be inserted efficiently into the chain as an O(1) operation. diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainMetadata.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainMetadata.cs index f823b0bdf5..9e3c26a1f4 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainMetadata.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainMetadata.cs @@ -1,6 +1,6 @@ using System; using System.Linq; -using Silk.Net.Vulkan; +using Silk.NET.Vulkan; using Xunit; namespace PrototypeStructChaining.Test; diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs index 45c1e5b66d..fd329abd36 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChains.cs @@ -1,4 +1,4 @@ -using Silk.Net.Vulkan; +using Silk.NET.Vulkan; using Xunit; namespace PrototypeStructChaining.Test; diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainsAny.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainsAny.cs new file mode 100644 index 0000000000..ab15057480 --- /dev/null +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestChainsAny.cs @@ -0,0 +1,30 @@ +using Silk.NET.Vulkan; +using Xunit; + +namespace PrototypeStructChaining.Test; + +public class TestChainsAny +{ + [Fact] + public unsafe void TestAddNextUnchecked() + { + var accelerationStructureFeatures = new PhysicalDeviceAccelerationStructureFeaturesKhr(); + accelerationStructureFeatures + .AddNextAny(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + .AddNextAny(out DeviceCreateInfo deviceCreateInfo); + + // Ensure all pointers set correctly + Assert.Equal((nint) (&indexingFeatures), (nint) accelerationStructureFeatures.PNext); + Assert.Equal((nint) (&deviceCreateInfo), (nint) indexingFeatures.PNext); + Assert.Equal(0, (nint) deviceCreateInfo.PNext); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeatures.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFeatures.SType); + Assert.Equal(StructureType.DeviceCreateInfo, deviceCreateInfo.SType); + + // Check indices + Assert.Equal(1, accelerationStructureFeatures.IndexOfAny(ref indexingFeatures)); + Assert.Equal(2, accelerationStructureFeatures.IndexOfAny(ref deviceCreateInfo)); + } +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs index abf2e22595..91c91d0aeb 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestCompilation.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; -using Silk.Net.Vulkan; +using Silk.NET.Vulkan; using Xunit; namespace PrototypeStructChaining.Test; @@ -25,7 +25,7 @@ public class TestCompilation private static readonly string CodeTemplate = @" using System; -using Silk.Net.Vulkan; +using Silk.NET.Vulkan; public class Test {{ @@ -79,6 +79,19 @@ public void TestCantAddUnsupportedNext() Assert.Equal("CS0315", error.Id); } + [Fact] + public void TestCanAddUnsupportedNextUsingAny() + { + var diagnostics = CheckCompile + ( + @"PhysicalDeviceFeatures2 + .Chain(out var features2) + .AddNextAny(out DeviceCreateInfo createInfo);" + ); + + Assert.Empty(diagnostics); + } + [Fact] public void TestCanAddSupportedNext() { diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs index e1504b67d3..fe83c428cb 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs @@ -1,6 +1,6 @@ using System; using System.Linq; -using Silk.Net.Vulkan; +using Silk.NET.Vulkan; using Xunit; namespace PrototypeStructChaining.Test; @@ -10,8 +10,12 @@ public class TestManagedChains [Fact] public unsafe void TestManagedChain() { - using var chain = new ManagedChain(); + using var chain = ManagedChain.Create + ( + default(PhysicalDeviceFeatures2), + default(PhysicalDeviceDescriptorIndexingFeatures), + default(PhysicalDeviceAccelerationStructureFeaturesKhr) + ); // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); @@ -28,7 +32,12 @@ public unsafe void TestManagedChain() public unsafe void TestManagedChainReplaceHead() { using var chain = - new ManagedChain(); + ManagedChain.Create + ( + default(DeviceCreateInfo), + default(PhysicalDeviceFeatures2), + default(PhysicalDeviceDescriptorIndexingFeatures) + ); // Ensure all STypes set correctly Assert.Equal(StructureType.DeviceCreateInfo, chain.Head.SType); @@ -62,7 +71,7 @@ public unsafe void TestManagedChainReplaceHead() [Fact] public unsafe void TestManagedChainReplaceMiddle() { - using var chain = new ManagedChain ( item1: new PhysicalDeviceDescriptorIndexingFeatures @@ -105,12 +114,13 @@ public unsafe void TestManagedChainReplaceMiddle() // As is the SType Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + chain.Dispose(); } [Fact] public unsafe void TestManagedChainDuplicate() { - using var chain = new ManagedChain + using var chain = ManagedChain.Create ( item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true} ); @@ -142,12 +152,23 @@ public unsafe void TestManagedChainDuplicate() // Check we have new copies Assert.NotEqual((nint) chain.HeadPtr, (nint) newChain.HeadPtr); Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); + + // Test equality + Assert.Equal(chain, newChain); + Assert.True(chain == newChain); + + // Modify second chain + newChain.Item1 = default; + + // Test equality + Assert.NotEqual(chain, newChain); + Assert.False(chain == newChain); } [Fact] - public unsafe void TestManagedChainAppend() + public unsafe void TestManagedChainAdd() { - using var chain = new ManagedChain + using var chain = ManagedChain.Create ( item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true} ); @@ -163,7 +184,7 @@ public unsafe void TestManagedChainAppend() // Check flag set Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); - using var newChain = chain.Append(); + using var newChain = chain.Add(default(PhysicalDeviceAccelerationStructureFeaturesKhr)); // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, newChain.Head.SType); @@ -244,7 +265,7 @@ public unsafe void TestManagedChainLoad() // Loads a new managed chain from an unmanaged chain using var managedChain = - new ManagedChain(out var errors, unmanagedChain); // Check we had no loading errors @@ -290,10 +311,16 @@ public void TestManagedChainLoadWithError() PhysicalDeviceFeatures2>(out var errors, unmanagedChain); // Check for errors + var errorsArray = errors.Split(new[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries); + Assert.Equal(2, errorsArray.Length); + Assert.Equal + ( + "The unmanaged chain has a structure type PhysicalDeviceFeatures2Khr at position 2; expected PhysicalDeviceAccelerationStructureFeaturesKhr", + errorsArray[0] + ); Assert.Equal ( - @"The unmanaged chain has a structure type PhysicalDeviceFeatures2Khr at position 2; expected PhysicalDeviceAccelerationStructureFeaturesKhr -The unmanaged chain was length 4, expected length 5", errors + "The unmanaged chain was length 4, expected length 5", errorsArray[1] ); // Despite the errors indexing features was at the right location so was loaded @@ -331,7 +358,7 @@ public void TestManagedChainLoadWithErrorTooLong() [Fact] public void TestReadOnlyList() { - using var chain = new ManagedChain(); Assert.Equal(3, chain.Count); @@ -355,7 +382,7 @@ public void TestReadOnlyList() [Fact] public void TestDeconstructor() { - using var chain = new ManagedChain(); var (physicalDeviceFeatures2, indexingFeatures, accelerationStructureFeaturesKhr) = chain; diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChainsAny.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChainsAny.cs new file mode 100644 index 0000000000..7b6c69018b --- /dev/null +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChainsAny.cs @@ -0,0 +1,193 @@ +using System; +using System.Linq; +using Silk.NET.Vulkan; +using Xunit; + +namespace PrototypeStructChaining.Test; + +public class TestManagedChainsAny +{ + [Fact] + public unsafe void TestManagedChainAny() + { + using var chain = ManagedChain.CreateAny + ( + default(PhysicalDeviceFeatures2), + default(PhysicalDeviceDescriptorIndexingFeatures), + default(DeviceCreateInfo) + ); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + Assert.Equal(StructureType.DeviceCreateInfo, chain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); + Assert.Equal(0, (nint) chain.Item2.PNext); + } + + [Fact] + public unsafe void TestManagedChainDuplicateAny() + { + using var chain = ManagedChain.CreateAny + ( + item1: new DeviceCreateInfo {Flags = 1U} + ); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.DeviceCreateInfo, chain.Item1.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal(0, (nint) chain.Item1.PNext); + + // Check flag set + Assert.Equal(1U, chain.Item1.Flags); + + using var newChain = chain.DuplicateAny(); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.DeviceCreateInfo, chain.Item1.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal(0, (nint) chain.Item1.PNext); + + // Check flag set + Assert.Equal(1U, chain.Item1.Flags); + + // Check we have new copies + Assert.NotEqual((nint) chain.HeadPtr, (nint) newChain.HeadPtr); + Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); + + // Test equality + Assert.Equal(chain, newChain); + Assert.True(chain == newChain); + } + + [Fact] + public unsafe void TestManagedChainAddAny() + { + using var chain = ManagedChain.Create + ( + item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true} + ); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal(0, (nint) chain.Item1.PNext); + + // Check flag set + Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + using var newChain = chain.AddAny(default(DeviceCreateInfo)); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, newChain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, newChain.Item1.SType); + Assert.Equal(StructureType.DeviceCreateInfo, newChain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) newChain.Item1Ptr, (nint) newChain.Head.PNext); + Assert.Equal((nint) newChain.Item2Ptr, (nint) newChain.Item1.PNext); + Assert.Equal(0, (nint) newChain.Item2.PNext); + + // Check flag still set + Assert.True(newChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + // Check we have new copies + Assert.NotEqual((nint) chain.HeadPtr, (nint) newChain.HeadPtr); + Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); + } + + [Fact] + public unsafe void TestManagedChainTruncateAny() + { + using var chain = + ManagedChain.CreateAny< + PhysicalDeviceFeatures2, + PhysicalDeviceDescriptorIndexingFeatures, + DeviceCreateInfo> + ( + item2: new DeviceCreateInfo {Flags = 1U} + ); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + Assert.Equal(StructureType.DeviceCreateInfo, chain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal((nint) chain.Item2Ptr, (nint) chain.Item1.PNext); + Assert.Equal(0, (nint) chain.Item2.PNext); + + // Check flag set + Assert.Equal(1U, chain.Item2.Flags); + + using var newChain = chain.TruncateAny(out var deviceCreateInfo); + + Assert.Equal(2, newChain.Count); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, newChain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, newChain.Item1.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) newChain.Item1Ptr, (nint) newChain.Head.PNext); + Assert.Equal(0, (nint) newChain.Item1.PNext); + + // Check removed type flag + Assert.Equal(1U, deviceCreateInfo.Flags); + + // Check we have new copies + Assert.NotEqual((nint) chain.HeadPtr, (nint) newChain.HeadPtr); + Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); + + // NOTE: As the new chain is valid, we can use Truncate on it + using var finalChain = newChain.Truncate(out var indexingFeatures); + } + + [Fact] + public unsafe void TestManagedChainLoadAny() + { + // Load an unmanaged chain + var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + { + ShaderInputAttachmentArrayDynamicIndexing = true + }; + PhysicalDeviceFeatures2 + .Chain(out var unmanagedChain) + .SetNext(ref indexingFeatures) + .AddNextAny(out DeviceCreateInfo deviceCreateInfo); + + // Loads a new managed chain from an unmanaged chain + using var managedChain = + ManagedChain.LoadAny(out var errors, unmanagedChain); + + // Check we had no loading errors + Assert.Equal("", errors); + + // Check the flag still set + Assert.True(managedChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, managedChain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, managedChain.Item1.SType); + Assert.Equal(StructureType.DeviceCreateInfo, managedChain.Item2.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) managedChain.Item1Ptr, (nint) managedChain.Head.PNext); + Assert.Equal((nint) managedChain.Item2Ptr, (nint) managedChain.Item1.PNext); + Assert.Equal(0, (nint) managedChain.Item2.PNext); + } +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/BaseInStructure.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/BaseInStructure.cs index dee01f2685..5e71dd6f11 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/BaseInStructure.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/BaseInStructure.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; /// /// Header struct of all structs. @@ -19,7 +19,7 @@ public struct BaseInStructure : IChainable /// /// The next struct in the chain, if any; otherwise . /// - public unsafe void* PNext; + public unsafe BaseInStructure* PNext; /// /// Note, this cannot coerce the type as 'guaranteed by the `IStructuredType` interface. diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Buffer.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Buffer.cs new file mode 100644 index 0000000000..37044ff381 --- /dev/null +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Buffer.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Silk.NET.Vulkan; + +/// +/// PlaceHolder - to ensure disambiguation works. +/// +[Obsolete("This class is here to indicate the the real Silk.NET.Vulkan contains a `Buffer` class.")] +public class Buffer +{ +} diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs index 75106005dc..3e03c003e7 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/Chain.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; public static class Chain { @@ -33,7 +33,15 @@ public static class Chain /// .SetNext(ref accelerationStructureFeaturesKhr); /// /// - public static unsafe ref TChain SetNext + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref TChain SetNext ( this ref TChain chain, ref TNext value, @@ -41,6 +49,53 @@ public static unsafe ref TChain SetNext ) where TChain : struct, IChainStart where TNext : struct, IExtendsChain + => ref SetNextAny(ref chain, ref value, alwaysAdd); + + /// + /// Replaces a structure in the chain (if present, and is false), or adds it to the end. + /// + /// The current chain + /// A reference to the structure to update + /// Always adds to the end of the chain, even if an equivalent structure is present. + /// The type of the current chain + /// The type of the value + /// A reference to the value value in the chain + /// + /// Note that both the supplied chain, and the supplied value will have their `SType` correctly set. Further, + /// the supplied structure's will be overwritten. + /// To use + /// + /// var indexingFeatures = new PhysicalDeviceDescriptorIndexingFeatures + /// { + /// ShaderInputAttachmentArrayDynamicIndexing = true + /// }; + /// var accelerationStructureFeaturesKhr = new PhysicalDeviceAccelerationStructureFeaturesKhr + /// { + /// AccelerationStructure = true + /// }; + /// + /// PhysicalDeviceFeatures2 + /// .BaseInStructure(out var features2) + /// .SetNext(ref indexingFeatures) + /// .SetNext(ref accelerationStructureFeaturesKhr); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static unsafe ref TChain SetNextAny + ( + this ref TChain chain, + ref TNext value, + bool alwaysAdd = false + ) + where TChain : struct, IChainable + where TNext : struct, IChainable { // Ensure structure type of chain and value are set. chain.StructureType(); @@ -67,7 +122,7 @@ public static unsafe ref TChain SetNext } previousPtr = currentPtr; - currentPtr = (BaseInStructure*) nextPtr; + currentPtr = nextPtr; } while (currentPtr is not null); // Add value to end of chain @@ -97,9 +152,52 @@ public static unsafe ref TChain SetNext /// Note, the value is always added, even if an equivalent value is added in the chain already. Use /// to only add if not already present. /// - public static unsafe ref TChain AddNext(this ref TChain chain, out TNext next) + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref TChain AddNext(this ref TChain chain, out TNext next) where TChain : struct, IChainStart where TNext : struct, IExtendsChain + => ref AddNextAny(ref chain, out next); + + /// + /// Adds a structure to the end of the chain. + /// + /// The current chain + /// The structure added to the end of the chain + /// The type of the current chain + /// The type of the structure to add + /// The reference to the chain. + /// + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .BaseInStructure(out var features2) + /// .AddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures) + /// .AddNext(out PhysicalDeviceAccelerationStructureFeaturesKhr accelerationStructureFeaturesKhr); + /// + /// Note, the value is always added, even if an equivalent value is added in the chain already. Use + /// to only add if not already present. + /// + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + /// + /// + /// + public static unsafe ref TChain AddNextAny(this ref TChain chain, out TNext next) + where TChain : struct, IChainable + where TNext : struct, IChainable { // Ensure structure type of chain is set. chain.StructureType(); @@ -108,7 +206,7 @@ public static unsafe ref TChain AddNext(this ref TChain chain, ou var currentPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); while (currentPtr->PNext is not null) { - currentPtr = (BaseInStructure*) currentPtr->PNext; + currentPtr = currentPtr->PNext; } // Create new entry and set it's structure type @@ -136,9 +234,50 @@ public static unsafe ref TChain AddNext(this ref TChain chain, ou /// .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures, out var added); /// /// - public static unsafe ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref TChain TryAddNext(this ref TChain chain, out TNext next, out bool added) where TChain : struct, IChainStart where TNext : struct, IExtendsChain + => ref TryAddNextAny(ref chain, out next, out added); + + /// + /// Tries to add a structure to the end of the chain. + /// + /// The current chain + /// The structure added to the end of the chain + /// Whether the structure was actually added + /// The type of the current chain + /// The type of the structure to add + /// The reference to the chain. + /// + /// Note that both the supplied chain, and the added structure will have their `SType` correctly set + /// To use specify the output type required, e.g.: + /// + /// PhysicalDeviceFeatures2 + /// .BaseInStructure(out var features2) + /// .TryAddNext(out PhysicalDeviceDescriptorIndexingFeatures indexingFeatures, out var added); + /// + /// + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + /// + /// + /// + public static unsafe ref TChain TryAddNextAny(this ref TChain chain, out TNext next, out bool added) + where TChain : struct, IChainable + where TNext : struct, IChainable { // Ensure structure type of chain is set. chain.StructureType(); @@ -163,7 +302,7 @@ public static unsafe ref TChain TryAddNext(this ref TChain chain, break; } - currentPtr = (BaseInStructure*) nextPtr; + currentPtr = nextPtr; } while (true); currentPtr->PNext = (BaseInStructure*) Unsafe.AsPointer(ref next); @@ -171,6 +310,71 @@ public static unsafe ref TChain TryAddNext(this ref TChain chain, return ref chain; } + /// + /// Returns the index of the in the , if present. + /// + /// The chain + /// The structure value + /// The type of the current chain + /// The type of the value + /// The zero-indexed index if found; otherwise -1. + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOf(this ref TChain chain, ref TNext value) + where TChain : struct, IChainStart + where TNext : struct, IExtendsChain + => IndexOfAny(ref chain, ref value); + + /// + /// Returns the index of the in the , if present. + /// + /// The chain + /// The structure value + /// The type of the current chain + /// The type of the value + /// The zero-indexed index if found; otherwise -1. + /// + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + /// + /// + /// + public static unsafe int IndexOfAny(this ref TChain chain, ref TNext value) + where TChain : struct, IChainable + where TNext : struct, IChainable + { + // Ensure structure type of chain is set. + chain.StructureType(); + + var index = 0; + var currentPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var valuePtr = (BaseInStructure*) Unsafe.AsPointer(ref value); + // Follow chain + do + { + if (currentPtr == valuePtr) + { + return index; + } + + currentPtr = currentPtr->PNext; + index++; + } while (currentPtr is not null); + + return -1; + } + /// /// Provides a set of all the s that can be extended by a . /// @@ -240,39 +444,6 @@ public static unsafe ref TChain TryAddNext(this ref TChain chain, Vulkan.StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr }; - /// - /// Returns the index of the in the , if present. - /// - /// The chain - /// The structure value - /// The type of the current chain - /// The type of the value - /// The zero-indexed index if found; otherwise -1. - public static unsafe int IndexOf(this ref TChain chain, ref TNext value) - where TChain : struct, IChainStart - where TNext : struct, IExtendsChain - { - // Ensure structure type of chain is set. - chain.StructureType(); - - var index = 0; - var currentPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var valuePtr = (BaseInStructure*) Unsafe.AsPointer(ref value); - // Follow chain - do - { - if (currentPtr == valuePtr) - { - return index; - } - - currentPtr = (BaseInStructure*) currentPtr->PNext; - index++; - } while (currentPtr is not null); - - return -1; - } - /// /// Gets the corresponding for a , if any. /// diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs index 3f6a136559..a0e6f61c27 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/DeviceCreateInfo.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; public struct DeviceCreateInfo : IChainStart { diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs index 867d9d658a..9ac897e448 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainStart.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; /// /// Marks a chainable struct as being allowed at the start of a chain. diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs index 9b47ca507c..03bf0e16ae 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; /// /// Base interface for any struct that has can set the next value. diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IExtendsChain.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IExtendsChain.cs index 5ef0a4ad99..306e008327 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IExtendsChain.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IExtendsChain.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; /// /// Marks a chainable struct indicating which chain this type diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs index f34ad05399..960038fac0 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IStructuredType.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; /// /// Base interface for any struct that has a field called `SType`, that must be correctly diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs index ae81ec1995..c46b5f41b6 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs @@ -1,16 +1,27 @@ // ReSharper disable StaticMemberInGenericType +#pragma warning disable CS0659, CS0660, CS0661 using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; /// -/// Static class for creating Managed Chains. +/// Base class for all Managed Chains. /// -public abstract class ManagedChain : IReadOnlyList, IDisposable +public abstract unsafe class ManagedChain : IReadOnlyList, IDisposable { + /// + /// Gets a pointer to the current head. + /// + public abstract BaseInStructure* HeadPtr { get; } + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public abstract int Size { get; } + /// public abstract IEnumerator GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() @@ -24,6 +35,19 @@ IEnumerator IEnumerable.GetEnumerator() /// public abstract IChainable this[int index] { get; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) + { + return !ReferenceEquals(null, obj) && + (ReferenceEquals(this, obj) || obj.GetType() == this.GetType() && MemoryEquals((ManagedChain) obj)); + } + + /// + /// Compares the supplied memory block with this one. + /// + protected abstract bool MemoryEquals(ManagedChain other); + /// public abstract void Dispose(); @@ -33,23 +57,38 @@ IEnumerator IEnumerable.GetEnumerator() /// The head of the chain. /// The chain type /// A new with 1 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedChain Create(TChain head = default) where TChain : struct, IChainStart - { - return new(head); - } + => new(head); /// - /// Loads a new with 1 items from an existing unmanaged chain. + /// Creates a new with 1 items. + /// + /// The head of the chain. + /// The chain type + /// A new with 1 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default) + where TChain : struct, IChainable + => new(head); + + /// + /// Loads a new with 1 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. /// A new with 1 items. - public static ManagedChain Load(out string errors, TChain chain) + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart - { - return new(out errors, chain); - } + => LoadAny(out var _, chain); /// /// Loads a new with 1 items from an existing unmanaged chain, @@ -57,10 +96,47 @@ public static ManagedChain Load(out string errors, TChain chain) /// /// The unmanaged chain to use as the basis of this chain. /// A new with 1 items. - public static ManagedChain Load(TChain chain) + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 1 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 1 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart - { - return new(out var _, chain); + => LoadAny(out errors, chain); + + /// + /// Loads a new with 1 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 1 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + errors = string.Empty; + return new ManagedChain(newHeadPtr); } /// @@ -71,25 +147,43 @@ public static ManagedChain Load(TChain chain) /// The chain type /// Type of Item 1. /// A new with 2 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedChain Create(TChain head = default, T1 item1 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain - { - return new(head, item1); - } + => new(head, item1); /// - /// Loads a new with 2 items from an existing unmanaged chain. + /// Creates a new with 2 items. + /// + /// The head of the chain. + /// Item 1. + /// The chain type + /// Type of Item 1. + /// A new with 2 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + => new(head, item1); + + /// + /// Loads a new with 2 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. /// A new with 2 items. - public static ManagedChain Load(out string errors, TChain chain) + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out var _, chain); /// /// Loads a new with 2 items from an existing unmanaged chain, @@ -97,11 +191,80 @@ public static ManagedChain Load(out string errors, TChai /// /// The unmanaged chain to use as the basis of this chain. /// A new with 2 items. - public static ManagedChain Load(TChain chain) + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 2 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 2 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain - { - return new(out var _, chain); + => LoadAny(out errors, chain); + + /// + /// Loads a new with 2 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 2 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); + existingPtr->PNext = null; + } + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } /// @@ -114,27 +277,48 @@ public static ManagedChain Load(TChain chain) /// Type of Item 1. /// Type of Item 2. /// A new with 3 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain - { - return new(head, item1, item2); - } + => new(head, item1, item2); /// - /// Loads a new with 3 items from an existing unmanaged chain. + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// A new with 3 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + => new(head, item1, item2); + + /// + /// Loads a new with 3 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. /// A new with 3 items. - public static ManagedChain Load(out string errors, TChain chain) + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out var _, chain); /// /// Loads a new with 3 items from an existing unmanaged chain, @@ -142,12 +326,104 @@ public static ManagedChain Load(out string error /// /// The unmanaged chain to use as the basis of this chain. /// A new with 3 items. - public static ManagedChain Load(TChain chain) + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 3 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 3 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain - { - return new(out var _, chain); + => LoadAny(out errors, chain); + + /// + /// Loads a new with 3 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 3 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 3"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 3"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 3"); + existingPtr->PNext = null; + } + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } /// @@ -162,29 +438,38 @@ public static ManagedChain Load(TChain chain) /// Type of Item 2. /// Type of Item 3. /// A new with 4 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain - { - return new(head, item1, item2, item3); - } + => new(head, item1, item2, item3); /// - /// Loads a new with 4 items from an existing unmanaged chain. + /// Creates a new with 4 items. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. /// A new with 4 items. - public static ManagedChain Load(out string errors, TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - { - return new(out errors, chain); - } + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + => new(head, item1, item2, item3); /// /// Loads a new with 4 items from an existing unmanaged chain, @@ -192,134 +477,368 @@ public static ManagedChain Load(out stri /// /// The unmanaged chain to use as the basis of this chain. /// A new with 4 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain - { - return new(out var _, chain); - } + => LoadAny(out var _, chain); /// - /// Creates a new with 5 items. + /// Loads a new with 4 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// A new with 5 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4); - } + /// The unmanaged chain to use as the basis of this chain. + /// A new with 4 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + => LoadAny(out var _, chain); /// - /// Loads a new with 5 items from an existing unmanaged chain. + /// Loads a new with 4 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 5 items. - public static ManagedChain Load(out string errors, TChain chain) + /// A new with 4 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out errors, chain); /// - /// Loads a new with 5 items from an existing unmanaged chain, - /// ignoring any errors. + /// Loads a new with 4 items from an existing unmanaged chain. /// + /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 5 items. - public static ManagedChain Load(TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - { - return new(out var _, chain); + /// A new with 4 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 4"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 4"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; + + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 4"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 4"); + existingPtr->PNext = null; + } + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 6 items. + /// Creates a new with 5 items. /// /// The head of the chain. /// Item 1. /// Item 2. /// Item 3. /// Item 4. - /// Item 5. /// The chain type /// Type of Item 1. /// Type of Item 2. /// Type of Item 3. /// Type of Item 4. - /// Type of Item 5. - /// A new with 6 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + /// A new with 5 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5); - } + => new(head, item1, item2, item3, item4); /// - /// Loads a new with 6 items from an existing unmanaged chain. + /// Creates a new with 5 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// A new with 5 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + => new(head, item1, item2, item3, item4); + + /// + /// Loads a new with 5 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 6 items. - public static ManagedChain Load(out string errors, TChain chain) + /// A new with 5 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out var _, chain); /// - /// Loads a new with 6 items from an existing unmanaged chain, + /// Loads a new with 5 items from an existing unmanaged chain, /// ignoring any errors. /// /// The unmanaged chain to use as the basis of this chain. - /// A new with 6 items. - public static ManagedChain Load(TChain chain) + /// A new with 5 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 5 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 5 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - { - return new(out var _, chain); + => LoadAny(out errors, chain); + + /// + /// Loads a new with 5 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 5 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 5"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 5"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; + + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 5"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; + + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 5"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 5"); + existingPtr->PNext = null; + } + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 7 items. + /// Creates a new with 6 items. /// /// The head of the chain. /// Item 1. @@ -327,65 +846,251 @@ public static ManagedChain LoadItem 3. /// Item 4. /// Item 5. - /// Item 6. /// The chain type /// Type of Item 1. /// Type of Item 2. /// Type of Item 3. /// Type of Item 4. /// Type of Item 5. - /// Type of Item 6. - /// A new with 7 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + /// A new with 6 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain where T4 : struct, IExtendsChain where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6); - } + => new(head, item1, item2, item3, item4, item5); /// - /// Loads a new with 7 items from an existing unmanaged chain. + /// Creates a new with 6 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// A new with 6 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + => new(head, item1, item2, item3, item4, item5); + + /// + /// Loads a new with 6 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 7 items. - public static ManagedChain Load(out string errors, TChain chain) + /// A new with 6 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain where T4 : struct, IExtendsChain where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out var _, chain); /// - /// Loads a new with 7 items from an existing unmanaged chain, + /// Loads a new with 6 items from an existing unmanaged chain, /// ignoring any errors. /// /// The unmanaged chain to use as the basis of this chain. - /// A new with 7 items. - public static ManagedChain Load(TChain chain) + /// A new with 6 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 6 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 6 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain where T3 : struct, IExtendsChain where T4 : struct, IExtendsChain where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - { - return new(out var _, chain); + => LoadAny(out errors, chain); + + /// + /// Loads a new with 6 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 6 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 6"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 6"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; + + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 6"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; + + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 6"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; + + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 6"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 6"); + existingPtr->PNext = null; + } + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 8 items. + /// Creates a new with 7 items. /// /// The head of the chain. /// Item 1. @@ -394,7 +1099,6 @@ public static ManagedChain LoadItem 4. /// Item 5. /// Item 6. - /// Item 7. /// The chain type /// Type of Item 1. /// Type of Item 2. @@ -402,47 +1106,10 @@ public static ManagedChain LoadType of Item 4. /// Type of Item 5. /// Type of Item 6. - /// Type of Item 7. - /// A new with 8 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6, item7); - } - - /// - /// Loads a new with 8 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - /// A new with 8 items. - public static ManagedChain Load(out string errors, TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - { - return new(out errors, chain); - } - - /// - /// Loads a new with 8 items from an existing unmanaged chain, - /// ignoring any errors. - /// - /// The unmanaged chain to use as the basis of this chain. - /// A new with 8 items. - public static ManagedChain Load(TChain chain) + /// A new with 7 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -450,13 +1117,10 @@ public static ManagedChain Load where T5 : struct, IExtendsChain where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - { - return new(out var _, chain); - } + => new(head, item1, item2, item3, item4, item5, item6); /// - /// Creates a new with 9 items. + /// Creates a new with 7 items. /// /// The head of the chain. /// Item 1. @@ -465,8 +1129,6 @@ public static ManagedChain LoadItem 4. /// Item 5. /// Item 6. - /// Item 7. - /// Item 8. /// The chain type /// Type of Item 1. /// Type of Item 2. @@ -474,30 +1136,31 @@ public static ManagedChain LoadType of Item 4. /// Type of Item 5. /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// A new with 9 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8); - } + /// A new with 7 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6); /// - /// Loads a new with 9 items from an existing unmanaged chain. + /// Loads a new with 7 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 9 items. - public static ManagedChain Load(out string errors, TChain chain) + /// A new with 7 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -505,57 +1168,38 @@ public static ManagedChain Load where T5 : struct, IExtendsChain where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out var _, chain); /// - /// Loads a new with 9 items from an existing unmanaged chain, + /// Loads a new with 7 items from an existing unmanaged chain, /// ignoring any errors. /// /// The unmanaged chain to use as the basis of this chain. - /// A new with 9 items. - public static ManagedChain Load(TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - { - return new(out var _, chain); - } + /// A new with 7 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + => LoadAny(out var _, chain); /// - /// Creates a new with 10 items. + /// Loads a new with 7 items from an existing unmanaged chain. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// The chain type - /// Type of Item 1. - /// Type of Item 2. - /// Type of Item 3. - /// Type of Item 4. - /// Type of Item 5. - /// Type of Item 6. - /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// A new with 10 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 7 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -563,57 +1207,173 @@ public static ManagedChain Create where T5 : struct, IExtendsChain where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9); - } + => LoadAny(out errors, chain); /// - /// Loads a new with 10 items from an existing unmanaged chain. + /// Loads a new with 7 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 10 items. - public static ManagedChain Load(out string errors, TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - { - return new(out errors, chain); - } + /// A new with 7 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; - /// - /// Loads a new with 10 items from an existing unmanaged chain, - /// ignoring any errors. - /// - /// The unmanaged chain to use as the basis of this chain. - /// A new with 10 items. - public static ManagedChain Load(TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - { - return new(out var _, chain); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 7"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 7"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; + + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 7"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; + + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 7"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; + + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 7"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; + + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 7"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 7"); + existingPtr->PNext = null; + } + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 11 items. + /// Creates a new with 8 items. /// /// The head of the chain. /// Item 1. @@ -623,9 +1383,6 @@ public static ManagedChain LoadItem 5. /// Item 6. /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. /// The chain type /// Type of Item 1. /// Type of Item 2. @@ -634,55 +1391,10 @@ public static ManagedChain LoadType of Item 5. /// Type of Item 6. /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// A new with 11 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10); - } - - /// - /// Loads a new with 11 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - /// A new with 11 items. - public static ManagedChain Load(out string errors, TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - { - return new(out errors, chain); - } - - /// - /// Loads a new with 11 items from an existing unmanaged chain, - /// ignoring any errors. - /// - /// The unmanaged chain to use as the basis of this chain. - /// A new with 11 items. - public static ManagedChain Load(TChain chain) + /// A new with 8 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -691,15 +1403,10 @@ public static ManagedChain Load where T5 : struct, IExtendsChain where T6 : struct, IExtendsChain where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - { - return new(out var _, chain); - } + => new(head, item1, item2, item3, item4, item5, item6, item7); /// - /// Creates a new with 12 items. + /// Creates a new with 8 items. /// /// The head of the chain. /// Item 1. @@ -709,10 +1416,6 @@ public static ManagedChain Load /// Item 5. /// Item 6. /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. /// The chain type /// Type of Item 1. /// Type of Item 2. @@ -721,12 +1424,32 @@ public static ManagedChain Load /// Type of Item 5. /// Type of Item 6. /// Type of Item 7. - /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// Type of Item 11. - /// A new with 12 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + /// A new with 8 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6, item7); + + /// + /// Loads a new with 8 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 8 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -735,21 +1458,39 @@ public static ManagedChain where T5 : struct, IExtendsChain where T6 : struct, IExtendsChain where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11); - } + => LoadAny(out var _, chain); /// - /// Loads a new with 12 items from an existing unmanaged chain. + /// Loads a new with 8 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 8 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 8 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 12 items. - public static ManagedChain Load(out string errors, TChain chain) + /// A new with 8 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -758,39 +1499,195 @@ public static ManagedChain where T5 : struct, IExtendsChain where T6 : struct, IExtendsChain where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out errors, chain); /// - /// Loads a new with 12 items from an existing unmanaged chain, - /// ignoring any errors. + /// Loads a new with 8 items from an existing unmanaged chain. /// + /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 12 items. - public static ManagedChain Load(TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - { - return new(out var _, chain); + /// A new with 8 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 8"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 8"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; + + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 8"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; + + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 8"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; + + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 8"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; + + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 8"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + newPtr = newPtr->PNext; + + T7 item7 = default; + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 8"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 8"); + existingPtr->PNext = null; + } + item7 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 13 items. + /// Creates a new with 9 items. /// /// The head of the chain. /// Item 1. @@ -801,10 +1698,6 @@ public static ManagedChain /// Item 6. /// Item 7. /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. /// The chain type /// Type of Item 1. /// Type of Item 2. @@ -814,60 +1707,10 @@ public static ManagedChain /// Type of Item 6. /// Type of Item 7. /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// Type of Item 11. - /// Type of Item 12. - /// A new with 13 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12); - } - - /// - /// Loads a new with 13 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - /// A new with 13 items. - public static ManagedChain Load(out string errors, TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - { - return new(out errors, chain); - } - - /// - /// Loads a new with 13 items from an existing unmanaged chain, - /// ignoring any errors. - /// - /// The unmanaged chain to use as the basis of this chain. - /// A new with 13 items. - public static ManagedChain Load(TChain chain) + /// A new with 9 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -877,16 +1720,10 @@ public static ManagedChain where T7 : struct, IExtendsChain where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - { - return new(out var _, chain); - } + => new(head, item1, item2, item3, item4, item5, item6, item7, item8); /// - /// Creates a new with 14 items. + /// Creates a new with 9 items. /// /// The head of the chain. /// Item 1. @@ -897,11 +1734,6 @@ public static ManagedChainItem 6. /// Item 7. /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. /// The chain type /// Type of Item 1. /// Type of Item 2. @@ -911,13 +1743,33 @@ public static ManagedChainType of Item 6. /// Type of Item 7. /// Type of Item 8. - /// Type of Item 9. - /// Type of Item 10. - /// Type of Item 11. - /// Type of Item 12. - /// Type of Item 13. - /// A new with 14 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + /// A new with 9 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6, item7, item8); + + /// + /// Loads a new with 9 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 9 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -927,22 +1779,40 @@ public static ManagedChain where T7 : struct, IExtendsChain where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); - } + => LoadAny(out var _, chain); /// - /// Loads a new with 14 items from an existing unmanaged chain. + /// Loads a new with 9 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 9 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 9 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 14 items. - public static ManagedChain Load(out string errors, TChain chain) + /// A new with 9 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -952,22 +1822,242 @@ public static ManagedChain where T7 : struct, IExtendsChain where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out errors, chain); /// - /// Loads a new with 14 items from an existing unmanaged chain, - /// ignoring any errors. + /// Loads a new with 9 items from an existing unmanaged chain. /// + /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 14 items. - public static ManagedChain Load(TChain chain) + /// A new with 9 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 9"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 9"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; + + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 9"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; + + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 9"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; + + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 9"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; + + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 9"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + newPtr = newPtr->PNext; + + T7 item7 = default; + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 9"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item7 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + newPtr = newPtr->PNext; + + T8 item8 = default; + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 9"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 9"); + existingPtr->PNext = null; + } + item8 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 10 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// A new with 10 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -978,16 +2068,10 @@ public static ManagedChain where T8 : struct, IExtendsChain where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - { - return new(out var _, chain); - } + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9); /// - /// Creates a new with 15 items. + /// Creates a new with 10 items. /// /// The head of the chain. /// Item 1. @@ -999,11 +2083,6 @@ public static ManagedChainItem 7. /// Item 8. /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - /// Item 14. /// The chain type /// Type of Item 1. /// Type of Item 2. @@ -1014,13 +2093,34 @@ public static ManagedChainType of Item 7. /// Type of Item 8. /// Type of Item 9. - /// Type of Item 10. - /// Type of Item 11. - /// Type of Item 12. - /// Type of Item 13. - /// Type of Item 14. - /// A new with 15 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + /// A new with 10 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9); + + /// + /// Loads a new with 10 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 10 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -1031,22 +2131,41 @@ public static ManagedChain where T8 : struct, IExtendsChain where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); - } + => LoadAny(out var _, chain); /// - /// Loads a new with 15 items from an existing unmanaged chain. + /// Loads a new with 10 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 10 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 10 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 15 items. - public static ManagedChain Load(out string errors, TChain chain) + /// A new with 10 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -1057,22 +2176,266 @@ public static ManagedChain where T8 : struct, IExtendsChain where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out errors, chain); /// - /// Loads a new with 15 items from an existing unmanaged chain, - /// ignoring any errors. + /// Loads a new with 10 items from an existing unmanaged chain. /// + /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 15 items. - public static ManagedChain Load(TChain chain) + /// A new with 10 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 10"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 10"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; + + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 10"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; + + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 10"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; + + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 10"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; + + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 10"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + newPtr = newPtr->PNext; + + T7 item7 = default; + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 10"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item7 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + newPtr = newPtr->PNext; + + T8 item8 = default; + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 10"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item8 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + newPtr = newPtr->PNext; + + T9 item9 = default; + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 10"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 10"); + existingPtr->PNext = null; + } + item9 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item9, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 11 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// A new with 11 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -1084,16 +2447,10 @@ public static ManagedChain where T9 : struct, IExtendsChain where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain - { - return new(out var _, chain); - } + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10); /// - /// Creates a new with 16 items. + /// Creates a new with 11 items. /// /// The head of the chain. /// Item 1. @@ -1106,11 +2463,6 @@ public static ManagedChainItem 8. /// Item 9. /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - /// Item 14. - /// Item 15. /// The chain type /// Type of Item 1. /// Type of Item 2. @@ -1122,13 +2474,35 @@ public static ManagedChainType of Item 8. /// Type of Item 9. /// Type of Item 10. - /// Type of Item 11. - /// Type of Item 12. - /// Type of Item 13. - /// Type of Item 14. - /// Type of Item 15. - /// A new with 16 items. - public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) + /// A new with 11 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10); + + /// + /// Loads a new with 11 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 11 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -1140,22 +2514,42 @@ public static ManagedChain where T9 : struct, IExtendsChain where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain - where T15 : struct, IExtendsChain - { - return new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); - } + => LoadAny(out var _, chain); /// - /// Loads a new with 16 items from an existing unmanaged chain. + /// Loads a new with 11 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 11 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 11 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 16 items. - public static ManagedChain Load(out string errors, TChain chain) + /// A new with 11 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain where T2 : struct, IExtendsChain @@ -1167,316 +2561,465 @@ public static ManagedChain where T9 : struct, IExtendsChain where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain - where T15 : struct, IExtendsChain - { - return new(out errors, chain); - } + => LoadAny(out errors, chain); /// - /// Loads a new with 16 items from an existing unmanaged chain, - /// ignoring any errors. + /// Loads a new with 11 items from an existing unmanaged chain. /// + /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - /// A new with 16 items. - public static ManagedChain Load(TChain chain) - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain - where T15 : struct, IExtendsChain - { - return new(out var _, chain); - } - -} + /// A new with 11 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart -{ - /// - /// Gets the size (in bytes) of the head structure. - /// - public static readonly int HeadSize = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; - /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. - /// - public static readonly int MemorySize = HeadSize; - - private nint _headPtr; + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } } - } + Marshal.StructureToPtr(item2, (nint) newPtr, false); - /// - /// Creates a new with 1 items from an existing memory block. - /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; - /// - /// Creates a new with 1 items. - /// - /// The head of the chain. - public ManagedChain(TChain head = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - HeadPtr->PNext = null; - } + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); - /// - /// Creates a new with 1 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - errors = string.Empty; - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; - /// - /// Creates a new with 1 by copying this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() - { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - return new ManagedChain(newHeadPtr); - } + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); - /// - /// Creates a new with 2 items, by appending to - /// the end of this chain. - /// - /// Item 1. - /// Type of Item 1 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T1 item1 = default) - where T1: struct, IExtendsChain - { - return new ManagedChain(this, item1); - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; - /// - public override IEnumerator GetEnumerator() - { - yield return Head; - } + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); - /// - public override int Count => 1; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; - /// - public override IChainable this[int index] - => index switch - { - 0 => Head, - _ => throw new IndexOutOfRangeException() - }; + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); - /// - /// Deconstructs this chain. - /// - /// The head of the chain. - public void Deconstruct(out TChain head) - { - head = Head; - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + newPtr = newPtr->PNext; - /// - public override void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); - if (headPtr == (nint)0) { - return; + T7 item7 = default; + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } + Marshal.StructureToPtr(item7, (nint) newPtr, false); - // Destroy all structures - Marshal.DestroyStructure(headPtr); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + newPtr = newPtr->PNext; - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} + T8 item8 = default; + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item8 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item8, (nint) newPtr, false); -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain -{ - /// - /// Gets the size (in bytes) of the head structure. - /// - public static readonly int HeadSize = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + newPtr = newPtr->PNext; - /// - /// Gets the offset to the start of . - /// - public static readonly int Item1Offset = HeadSize; + T9 item9 = default; + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item9 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item9, (nint) newPtr, false); - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item1Size = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + newPtr = newPtr->PNext; - /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. - /// - public static readonly int MemorySize = Item1Offset + Item1Size; - - private nint _headPtr; + T10 item10 = default; + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 11"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 11"); + existingPtr->PNext = null; + } + item10 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item10, (nint) newPtr, false); - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); + } /// - /// Gets or sets the head of the chain. + /// Creates a new with 12 items. /// - public TChain Head - { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; - } - } + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// A new with 12 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11); /// - /// Gets a pointer to the second item in the chain. + /// Creates a new with 12 items. /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// A new with 12 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11); /// - /// Gets or sets item #1 in the chain. + /// Loads a new with 12 items from an existing unmanaged chain, + /// ignoring any errors. /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set - { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + /// The unmanaged chain to use as the basis of this chain. + /// A new with 12 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + => LoadAny(out var _, chain); /// - /// Creates a new with 2 items from an existing memory block. + /// Loads a new with 12 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } + /// The unmanaged chain to use as the basis of this chain. + /// A new with 12 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + => LoadAny(out var _, chain); /// - /// Creates a new with 2 items. + /// Loads a new with 12 items from an existing unmanaged chain. /// - /// The head of the chain. - /// Item 1. - public ManagedChain(TChain head = default, T1 item1 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - Item1Ptr->PNext = null; - } + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 12 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + => LoadAny(out errors, chain); /// - /// Creates a new with 2 items from an existing unmanaged chain. + /// Loads a new with 12 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { + /// A new with 12 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; + var newPtr = (BaseInStructure*) newHeadPtr; - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 12"); } else { if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") @@ -1485,316 +3028,446 @@ public ManagedChain(out string errors, TChain chain) .Append(expectedStructureType) .AppendLine(); } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); - existingPtr->PNext = null; - } item1 = Unsafe.AsRef(existingPtr); } } Marshal.StructureToPtr(item1, (nint) newPtr, false); - // Create string of errors - errors = errorBuilder.ToString().Trim(); - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; - /// - /// Creates a new with 2 by copying this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() - { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - return new ManagedChain(newHeadPtr); - } - - /// - /// Creates a new with 2 items, by appending - /// to the end of this chain. - /// - /// The chain to append to. - /// Item 1. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T1 item1 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item1Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 1 - item1.StructureType(); - Marshal.StructureToPtr(item1, _headPtr + previousSize, false); + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; - /// - /// Creates a new with 1 items, by removing the last item - /// from this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() - { - return Truncate(out var _); - } + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); - /// - /// Creates a new with 1 items, by removing - /// from the end of this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate(out T1 item1) - { - item1 = Item1; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; - var newSize = MemorySize - Item1Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = null; - return new ManagedChain(newHeadPtr); - } + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); - /// - /// Creates a new with 3 items, by appending to - /// the end of this chain. - /// - /// Item 2. - /// Type of Item 2 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T2 item2 = default) - where T2: struct, IExtendsChain - { - return new ManagedChain(this, item2); - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; - /// - public override IEnumerator GetEnumerator() - { - yield return Head; - yield return Item1; - } + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); - /// - public override int Count => 2; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; - /// - public override IChainable this[int index] - => index switch - { - 0 => Head, - 1 => Item1, - _ => throw new IndexOutOfRangeException() - }; + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); - /// - /// Deconstructs this chain. - /// - /// The head of the chain. - /// Item 1. - public void Deconstruct(out TChain head, out T1 item1) - { - head = Head; - item1 = Item1; - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + newPtr = newPtr->PNext; - /// - public override void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); - if (headPtr == (nint)0) { - return; + T7 item7 = default; + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } + Marshal.StructureToPtr(item7, (nint) newPtr, false); - // Destroy all structures - Marshal.DestroyStructure(headPtr); - Marshal.DestroyStructure(headPtr + Item1Offset); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + newPtr = newPtr->PNext; - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} + T8 item8 = default; + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item8 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item8, (nint) newPtr, false); -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain -{ - /// - /// Gets the size (in bytes) of the head structure. - /// - public static readonly int HeadSize = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + newPtr = newPtr->PNext; - /// - /// Gets the offset to the start of . - /// - public static readonly int Item1Offset = HeadSize; + T9 item9 = default; + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item9 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item9, (nint) newPtr, false); - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item1Size = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + newPtr = newPtr->PNext; - /// - /// Gets the offset to the start of . - /// - public static readonly int Item2Offset = Item1Offset + Item1Size; + T10 item10 = default; + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item10 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item10, (nint) newPtr, false); - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item2Size = Marshal.SizeOf(); - - /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. - /// - public static readonly int MemorySize = Item2Offset + Item2Size; - - private nint _headPtr; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + newPtr = newPtr->PNext; - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; + T11 item11 = default; + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 12"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 12"); + existingPtr->PNext = null; + } + item11 = Unsafe.AsRef(existingPtr); + } } - } + Marshal.StructureToPtr(item11, (nint) newPtr, false); - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); + } /// - /// Gets or sets item #1 in the chain. + /// Creates a new with 13 items. /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set - { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// A new with 13 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12); /// - /// Gets a pointer to the second item in the chain. + /// Creates a new with 13 items. /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// A new with 13 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12); /// - /// Gets or sets item #2 in the chain. + /// Loads a new with 13 items from an existing unmanaged chain, + /// ignoring any errors. /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + /// The unmanaged chain to use as the basis of this chain. + /// A new with 13 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + => LoadAny(out var _, chain); /// - /// Creates a new with 3 items from an existing memory block. + /// Loads a new with 13 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } + /// The unmanaged chain to use as the basis of this chain. + /// A new with 13 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + => LoadAny(out var _, chain); /// - /// Creates a new with 3 items. + /// Loads a new with 13 items from an existing unmanaged chain. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - Item2Ptr->PNext = null; - } + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 13 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + => LoadAny(out errors, chain); /// - /// Creates a new with 3 items from an existing unmanaged chain. + /// Loads a new with 13 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { + /// A new with 13 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; + var newPtr = (BaseInStructure*) newHeadPtr; - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 3"); + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 13"); } else { if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") @@ -1808,14 +3481,14 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 3"); + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 13"); } else { if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") @@ -1824,362 +3497,456 @@ public ManagedChain(out string errors, TChain chain) .Append(expectedStructureType) .AppendLine(); } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 3"); - existingPtr->PNext = null; - } item2 = Unsafe.AsRef(existingPtr); } } Marshal.StructureToPtr(item2, (nint) newPtr, false); - // Create string of errors - errors = errorBuilder.ToString().Trim(); - } - - /// - /// Creates a new with 3 by copying this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() - { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - return new ManagedChain(newHeadPtr); - } - - /// - /// Creates a new with 3 items, by appending - /// to the end of this chain. - /// - /// The chain to append to. - /// Item 2. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T2 item2 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item2Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 2 - item2.StructureType(); - Marshal.StructureToPtr(item2, _headPtr + previousSize, false); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; - } - - /// - /// Creates a new with 2 items, by removing the last item - /// from this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() - { - return Truncate(out var _); - } + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); - /// - /// Creates a new with 2 items, by removing - /// from the end of this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate(out T2 item2) - { - item2 = Item2; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; - var newSize = MemorySize - Item2Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = null; - return new ManagedChain(newHeadPtr); - } + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); - /// - /// Creates a new with 4 items, by appending to - /// the end of this chain. - /// - /// Item 3. - /// Type of Item 3 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T3 item3 = default) - where T3: struct, IExtendsChain - { - return new ManagedChain(this, item3); - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; - /// - public override IEnumerator GetEnumerator() - { - yield return Head; - yield return Item1; - yield return Item2; - } + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); - /// - public override int Count => 3; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; - /// - public override IChainable this[int index] - => index switch - { - 0 => Head, - 1 => Item1, - 2 => Item2, - _ => throw new IndexOutOfRangeException() - }; + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); - /// - /// Deconstructs this chain. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2) - { - head = Head; - item1 = Item1; - item2 = Item2; - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + newPtr = newPtr->PNext; - /// - public override void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); - if (headPtr == (nint)0) { - return; + T7 item7 = default; + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item7 = Unsafe.AsRef(existingPtr); + } } + Marshal.StructureToPtr(item7, (nint) newPtr, false); - // Destroy all structures - Marshal.DestroyStructure(headPtr); - Marshal.DestroyStructure(headPtr + Item1Offset); - Marshal.DestroyStructure(headPtr + Item2Offset); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + newPtr = newPtr->PNext; - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} + T8 item8 = default; + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item8 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item8, (nint) newPtr, false); -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain -{ - /// - /// Gets the size (in bytes) of the head structure. - /// - public static readonly int HeadSize = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + newPtr = newPtr->PNext; - /// - /// Gets the offset to the start of . - /// - public static readonly int Item1Offset = HeadSize; + T9 item9 = default; + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item9 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item9, (nint) newPtr, false); - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item1Size = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + newPtr = newPtr->PNext; - /// - /// Gets the offset to the start of . - /// - public static readonly int Item2Offset = Item1Offset + Item1Size; + T10 item10 = default; + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item10 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item10, (nint) newPtr, false); - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item2Size = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + newPtr = newPtr->PNext; - /// - /// Gets the offset to the start of . - /// - public static readonly int Item3Offset = Item2Offset + Item2Size; + T11 item11 = default; + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item11 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item11, (nint) newPtr, false); - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item3Size = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + newPtr = newPtr->PNext; - /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. - /// - public static readonly int MemorySize = Item3Offset + Item3Size; - - private nint _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; + T12 item12 = default; + expectedStructureType = item12.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 13"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 13"); + existingPtr->PNext = null; + } + item12 = Unsafe.AsRef(existingPtr); + } } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); + Marshal.StructureToPtr(item12, (nint) newPtr, false); - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set - { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - - /// - /// Gets or sets item #2 in the chain. + /// Creates a new with 14 items. /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// A new with 14 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); /// - /// Gets a pointer to the second item in the chain. + /// Creates a new with 14 items. /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// A new with 14 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13); /// - /// Gets or sets item #3 in the chain. + /// Loads a new with 14 items from an existing unmanaged chain, + /// ignoring any errors. /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + /// The unmanaged chain to use as the basis of this chain. + /// A new with 14 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + => LoadAny(out var _, chain); /// - /// Creates a new with 4 items from an existing memory block. + /// Loads a new with 14 items from an existing unmanaged chain, + /// ignoring any errors. /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } + /// The unmanaged chain to use as the basis of this chain. + /// A new with 14 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + => LoadAny(out var _, chain); /// - /// Creates a new with 4 items. + /// Loads a new with 14 items from an existing unmanaged chain. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - Item3Ptr->PNext = null; - } + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 14 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + => LoadAny(out errors, chain); /// - /// Creates a new with 4 items from an existing unmanaged chain. + /// Loads a new with 14 items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { + /// A new with 14 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; + var newPtr = (BaseInStructure*) newHeadPtr; - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; T1 item1 = default; var expectedStructureType = item1.StructureType(); if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 4"); + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 14"); } else { if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") @@ -2193,14 +3960,14 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item1, (nint) newPtr, false); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; T2 item2 = default; expectedStructureType = item2.StructureType(); if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 4"); + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 14"); } else { if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") @@ -2214,14 +3981,14 @@ public ManagedChain(out string errors, TChain chain) } Marshal.StructureToPtr(item2, (nint) newPtr, false); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; T3 item3 = default; expectedStructureType = item3.StructureType(); if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 4"); + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 14"); } else { if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") @@ -2230,734 +3997,6276 @@ public ManagedChain(out string errors, TChain chain) .Append(expectedStructureType) .AppendLine(); } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 4"); - existingPtr->PNext = null; - } item3 = Unsafe.AsRef(existingPtr); } } Marshal.StructureToPtr(item3, (nint) newPtr, false); - // Create string of errors - errors = errorBuilder.ToString().Trim(); - } - - /// - /// Creates a new with 4 by copying this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() - { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - return new ManagedChain(newHeadPtr); - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; - /// - /// Creates a new with 4 items, by appending - /// to the end of this chain. - /// - /// The chain to append to. - /// Item 3. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T3 item3 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item3Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 3 - item3.StructureType(); - Marshal.StructureToPtr(item3, _headPtr + previousSize, false); + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 14"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; - /// - /// Creates a new with 3 items, by removing the last item - /// from this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() - { - return Truncate(out var _); - } + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 14"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); - /// - /// Creates a new with 3 items, by removing - /// from the end of this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate(out T3 item3) - { - item3 = Item3; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; - var newSize = MemorySize - Item3Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = null; - return new ManagedChain(newHeadPtr); - } + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 14"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); - /// - /// Creates a new with 5 items, by appending to - /// the end of this chain. - /// - /// Item 4. - /// Type of Item 4 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T4 item4 = default) - where T4: struct, IExtendsChain - { - return new ManagedChain(this, item4); - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + newPtr = newPtr->PNext; - /// - public override IEnumerator GetEnumerator() - { - yield return Head; - yield return Item1; - yield return Item2; - yield return Item3; - } + T7 item7 = default; + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 14"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item7 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item7, (nint) newPtr, false); - /// - public override int Count => 4; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + newPtr = newPtr->PNext; - /// - public override IChainable this[int index] - => index switch - { - 0 => Head, - 1 => Item1, - 2 => Item2, - 3 => Item3, - _ => throw new IndexOutOfRangeException() - }; + T8 item8 = default; + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 14"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item8 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item8, (nint) newPtr, false); - /// - /// Deconstructs this chain. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3) - { - head = Head; - item1 = Item1; - item2 = Item2; - item3 = Item3; - } + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + newPtr = newPtr->PNext; - /// - public override void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); - if (headPtr == (nint)0) { - return; + T9 item9 = default; + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 14"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item9 = Unsafe.AsRef(existingPtr); + } } + Marshal.StructureToPtr(item9, (nint) newPtr, false); - // Destroy all structures - Marshal.DestroyStructure(headPtr); - Marshal.DestroyStructure(headPtr + Item1Offset); - Marshal.DestroyStructure(headPtr + Item2Offset); - Marshal.DestroyStructure(headPtr + Item3Offset); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + newPtr = newPtr->PNext; - // Free memory block - Marshal.FreeHGlobal(headPtr); - } -} + T10 item10 = default; + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 14"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item10 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item10, (nint) newPtr, false); -/// -/// A safely manages the pointers of a managed structure chain. -/// -/// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain -{ - /// - /// Gets the size (in bytes) of the head structure. - /// - public static readonly int HeadSize = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + newPtr = newPtr->PNext; - /// - /// Gets the offset to the start of . - /// - public static readonly int Item1Offset = HeadSize; + T11 item11 = default; + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 14"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item11 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item11, (nint) newPtr, false); - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item1Size = Marshal.SizeOf(); + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + newPtr = newPtr->PNext; - /// - /// Gets the offset to the start of . - /// - public static readonly int Item2Offset = Item1Offset + Item1Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item2Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item3Offset = Item2Offset + Item2Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item3Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item4Offset = Item3Offset + Item3Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item4Size = Marshal.SizeOf(); - - /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. - /// - public static readonly int MemorySize = Item4Offset + Item4Size; - - private nint _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set - { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef(Item4Ptr); - set - { - value.StructureType(); - var ptr = Item4Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Creates a new with 5 items from an existing memory block. - /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } - - /// - /// Creates a new with 5 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - Item4Ptr->PNext = null; - } - - /// - /// Creates a new with 5 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 5"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 5"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T3 item3 = default; - expectedStructureType = item3.StructureType(); + T12 item12 = default; + expectedStructureType = item12.StructureType(); if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 5"); + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 14"); } else { if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(existingPtr->SType) - .Append(" at position 4; expected ") + .Append(" at position 13; expected ") .Append(expectedStructureType) .AppendLine(); } else { - item3 = Unsafe.AsRef(existingPtr); + item12 = Unsafe.AsRef(existingPtr); } } - Marshal.StructureToPtr(item3, (nint) newPtr, false); + Marshal.StructureToPtr(item12, (nint) newPtr, false); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + newPtr = newPtr->PNext; - T4 item4 = default; - expectedStructureType = item4.StructureType(); + T13 item13 = default; + expectedStructureType = item13.StructureType(); if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 5"); + errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 14"); } else { if (existingPtr->SType != expectedStructureType) { errorBuilder.Append("The unmanaged chain has a structure type ") .Append(existingPtr->SType) - .Append(" at position 5; expected ") + .Append(" at position 14; expected ") .Append(expectedStructureType) .AppendLine(); } else { if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 5"); + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 14"); existingPtr->PNext = null; } - item4 = Unsafe.AsRef(existingPtr); + item13 = Unsafe.AsRef(existingPtr); } } - Marshal.StructureToPtr(item4, (nint) newPtr, false); + Marshal.StructureToPtr(item13, (nint) newPtr, false); // Create string of errors errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 5 by copying this chain. + /// Creates a new with 15 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// A new with 15 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); + + /// + /// Creates a new with 15 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// A new with 15 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14); + + /// + /// Loads a new with 15 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 15 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + => LoadAny(out var _, chain); + + /// + /// Loads a new with 15 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 15 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 15 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 15 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + => LoadAny(out errors, chain); + + /// + /// Loads a new with 15 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 15 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; + + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; + + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; + + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; + + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + newPtr = newPtr->PNext; + + T7 item7 = default; + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item7 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + newPtr = newPtr->PNext; + + T8 item8 = default; + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item8 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + newPtr = newPtr->PNext; + + T9 item9 = default; + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item9 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item9, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + newPtr = newPtr->PNext; + + T10 item10 = default; + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item10 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item10, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + newPtr = newPtr->PNext; + + T11 item11 = default; + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item11 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item11, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + newPtr = newPtr->PNext; + + T12 item12 = default; + expectedStructureType = item12.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item12 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item12, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + newPtr = newPtr->PNext; + + T13 item13 = default; + expectedStructureType = item13.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 14; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item13 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item13, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item14Offset); + newPtr = newPtr->PNext; + + T14 item14 = default; + expectedStructureType = item14.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 15"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 15; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 15"); + existingPtr->PNext = null; + } + item14 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item14, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 16 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// Item 15. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. + /// A new with 16 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Create(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); + + /// + /// Creates a new with 16 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// Item 15. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. + /// A new with 16 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + where T15 : struct, IChainable + => new(head, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15); + + /// + /// Loads a new with 16 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 16 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + => LoadAny(out var _, chain); + + /// + /// Loads a new with 16 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 16 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + where T15 : struct, IChainable + => LoadAny(out var _, chain); + + /// + /// Loads a new with 16 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 16 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(out string errors, TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + => LoadAny(out errors, chain); + + /// + /// Loads a new with 16 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 16 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + where T15 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + newPtr = newPtr->PNext; + + T2 item2 = default; + expectedStructureType = item2.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 3; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item2 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item2, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + newPtr = newPtr->PNext; + + T3 item3 = default; + expectedStructureType = item3.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 4; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item3 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item3, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + newPtr = newPtr->PNext; + + T4 item4 = default; + expectedStructureType = item4.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 5; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item4 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item4, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + newPtr = newPtr->PNext; + + T5 item5 = default; + expectedStructureType = item5.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 6; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item5 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item5, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + newPtr = newPtr->PNext; + + T6 item6 = default; + expectedStructureType = item6.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 7; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item6 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item6, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + newPtr = newPtr->PNext; + + T7 item7 = default; + expectedStructureType = item7.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 8; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item7 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item7, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + newPtr = newPtr->PNext; + + T8 item8 = default; + expectedStructureType = item8.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 9; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item8 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item8, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + newPtr = newPtr->PNext; + + T9 item9 = default; + expectedStructureType = item9.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 10; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item9 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item9, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + newPtr = newPtr->PNext; + + T10 item10 = default; + expectedStructureType = item10.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 11; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item10 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item10, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + newPtr = newPtr->PNext; + + T11 item11 = default; + expectedStructureType = item11.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 12; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item11 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item11, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + newPtr = newPtr->PNext; + + T12 item12 = default; + expectedStructureType = item12.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 13; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item12 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item12, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + newPtr = newPtr->PNext; + + T13 item13 = default; + expectedStructureType = item13.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 14; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item13 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item13, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item14Offset); + newPtr = newPtr->PNext; + + T14 item14 = default; + expectedStructureType = item14.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 15; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + item14 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item14, (nint) newPtr, false); + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item15Offset); + newPtr = newPtr->PNext; + + T15 item15 = default; + expectedStructureType = item15.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 15, expected length 16"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 16; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 16"); + existingPtr->PNext = null; + } + item15 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item15, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); + } + +} + +/// +/// Static class providing extension methods for manipulating managed chains. +/// +/// The `Any` versions of chain methods do not validate that items belong in the chain, this is +/// useful for situations where the specification does not indicate required chain constraints. You should generally +/// try to use the none `Any` version in preference. +public static unsafe class ManagedChainExtensions +{ + /// + /// Creates a new with 1 by copying the . + /// + /// The chain. + /// The chain type + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + => chain.DuplicateAny(); + + /// + /// Creates a new with 1 by copying the . + /// + /// The chain. + /// The chain type + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 2 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T1 item1 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + => chain.AddAny(item1); + + /// + /// Creates a new with 2 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T1 item1 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 0 + item1.StructureType(); + Marshal.StructureToPtr(item1, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 2 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 2 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 1 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 1 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 1 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T1 item1) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + => chain.TruncateAny(out item1); + + /// + /// Creates a new with 1 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T1 item1) + where TChain : struct, IChainable + where T1 : struct, IChainable + { + // Retrieve last item. + item1 = chain.Item1; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item1Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 3 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T2 item2 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + => chain.AddAny(item2); + + /// + /// Creates a new with 3 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T2 item2 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 1 + item2.StructureType(); + Marshal.StructureToPtr(item2, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 3 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 3 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 2 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 2 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 2 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T2 item2) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + => chain.TruncateAny(out item2); + + /// + /// Creates a new with 2 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T2 item2) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + { + // Retrieve last item. + item2 = chain.Item2; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item2Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 4 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T3 item3 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + => chain.AddAny(item3); + + /// + /// Creates a new with 4 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T3 item3 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 2 + item3.StructureType(); + Marshal.StructureToPtr(item3, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 4 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 4 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 3 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 3 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 3 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T3 item3) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + => chain.TruncateAny(out item3); + + /// + /// Creates a new with 3 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T3 item3) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + { + // Retrieve last item. + item3 = chain.Item3; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item3Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 5 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T4 item4 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + => chain.AddAny(item4); + + /// + /// Creates a new with 5 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T4 item4 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 3 + item4.StructureType(); + Marshal.StructureToPtr(item4, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 5 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 5 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 4 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 4 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 4 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T4 item4) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + => chain.TruncateAny(out item4); + + /// + /// Creates a new with 4 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T4 item4) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + { + // Retrieve last item. + item4 = chain.Item4; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item4Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 6 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T5 item5 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + => chain.AddAny(item5); + + /// + /// Creates a new with 6 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T5 item5 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 4 + item5.StructureType(); + Marshal.StructureToPtr(item5, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 6 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 6 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 5 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 5 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 5 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T5 item5) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + => chain.TruncateAny(out item5); + + /// + /// Creates a new with 5 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T5 item5) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + { + // Retrieve last item. + item5 = chain.Item5; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item5Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 7 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T6 item6 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + => chain.AddAny(item6); + + /// + /// Creates a new with 7 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T6 item6 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 5 + item6.StructureType(); + Marshal.StructureToPtr(item6, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 7 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 7 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 6 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 6 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 6 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T6 item6) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + => chain.TruncateAny(out item6); + + /// + /// Creates a new with 6 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T6 item6) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + { + // Retrieve last item. + item6 = chain.Item6; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item6Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 8 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T7 item7 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + => chain.AddAny(item7); + + /// + /// Creates a new with 8 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T7 item7 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 6 + item7.StructureType(); + Marshal.StructureToPtr(item7, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 8 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 8 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 7 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 7 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 7 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T7 item7) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + => chain.TruncateAny(out item7); + + /// + /// Creates a new with 7 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T7 item7) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + { + // Retrieve last item. + item7 = chain.Item7; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item7Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 9 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T8 item8 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + => chain.AddAny(item8); + + /// + /// Creates a new with 9 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T8 item8 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 7 + item8.StructureType(); + Marshal.StructureToPtr(item8, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 9 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 9 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 8 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 8 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 8 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T8 item8) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + => chain.TruncateAny(out item8); + + /// + /// Creates a new with 8 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T8 item8) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + { + // Retrieve last item. + item8 = chain.Item8; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item8Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 10 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T9 item9 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + => chain.AddAny(item9); + + /// + /// Creates a new with 10 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T9 item9 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 8 + item9.StructureType(); + Marshal.StructureToPtr(item9, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 10 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 10 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 9 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 9 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 9 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T9 item9) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + => chain.TruncateAny(out item9); + + /// + /// Creates a new with 9 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T9 item9) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + { + // Retrieve last item. + item9 = chain.Item9; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item9Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 11 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T10 item10 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + => chain.AddAny(item10); + + /// + /// Creates a new with 11 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T10 item10 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 9 + item10.StructureType(); + Marshal.StructureToPtr(item10, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 11 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 11 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 10 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 10 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 10 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T10 item10) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + => chain.TruncateAny(out item10); + + /// + /// Creates a new with 10 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T10 item10) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + { + // Retrieve last item. + item10 = chain.Item10; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item10Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 12 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T11 item11 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + => chain.AddAny(item11); + + /// + /// Creates a new with 12 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T11 item11 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 10 + item11.StructureType(); + Marshal.StructureToPtr(item11, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 12 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 12 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 11 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 11 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 11 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T11 item11) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + => chain.TruncateAny(out item11); + + /// + /// Creates a new with 11 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T11 item11) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + { + // Retrieve last item. + item11 = chain.Item11; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item11Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 13 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T12 item12 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + => chain.AddAny(item12); + + /// + /// Creates a new with 13 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T12 item12 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 11 + item12.StructureType(); + Marshal.StructureToPtr(item12, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 13 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 13 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 12 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 12 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 12 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T12 item12) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + => chain.TruncateAny(out item12); + + /// + /// Creates a new with 12 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T12 item12) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + { + // Retrieve last item. + item12 = chain.Item12; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item12Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 14 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T13 item13 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + => chain.AddAny(item13); + + /// + /// Creates a new with 14 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T13 item13 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 12 + item13.StructureType(); + Marshal.StructureToPtr(item13, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 14 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 14 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 13 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 13 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 13 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T13 item13) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + => chain.TruncateAny(out item13); + + /// + /// Creates a new with 13 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T13 item13) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + { + // Retrieve last item. + item13 = chain.Item13; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item13Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item12Offset))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 15 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain Add(this ManagedChain chain, T14 item14 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + => chain.AddAny(item14); + + /// + /// Creates a new with 15 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T14 item14 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item 13 + item14.StructureType(); + Marshal.StructureToPtr(item14, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item14Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 15 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 15 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item14Offset); + return new ManagedChain(newHeadPtr); + } + + /// + /// Creates a new with 14 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 14 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 14 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T14 item14) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + => chain.TruncateAny(out item14); + + /// + /// Creates a new with 14 items, by removing + /// from the end of the . /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. /// - public ManagedChain Duplicate() - { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T14 item14) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + { + // Retrieve last item. + item14 = chain.Item14; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item14Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - return new ManagedChain(newHeadPtr); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item13Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 5 items, by appending - /// to the end of this chain. + /// Creates a new with 16 items, by appending to + /// the end of the . /// - /// The chain to append to. - /// Item 4. + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. /// - /// Do not forget to dispose the chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. /// - public ManagedChain(ManagedChain previous, T4 item4 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item4Size; + /// + public static ManagedChain Add(this ManagedChain chain, T15 item15 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + => chain.AddAny(item15); + + /// + /// Creates a new with 16 items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain AddAny(this ManagedChain chain, T15 item15 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + where T15 : struct, IChainable + { + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); - // Append item 4 - item4.StructureType(); - Marshal.StructureToPtr(item4, _headPtr + previousSize, false); + // Append item 14 + item15.StructureType(); + Marshal.StructureToPtr(item15, newHeadPtr + previousSize, false); // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item14Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item14Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item15Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 4 items, by removing the last item - /// from this chain. + /// Creates a new with 16 by copying the . /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. /// /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain Truncate() - { - return Truncate(out var _); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + => chain.DuplicateAny(); + + /// + /// Creates a new with 16 by copying the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + where T15 : struct, IChainable + { + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item14Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item14Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item15Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 4 items, by removing - /// from the end of this chain. + /// Creates a new with 15 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 15 items, by removing the last item + /// from the . /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + where T15 : struct, IChainable + => chain.TruncateAny(out var _); + + /// + /// Creates a new with 15 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T15 item15) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + where T2 : struct, IExtendsChain + where T3 : struct, IExtendsChain + where T4 : struct, IExtendsChain + where T5 : struct, IExtendsChain + where T6 : struct, IExtendsChain + where T7 : struct, IExtendsChain + where T8 : struct, IExtendsChain + where T9 : struct, IExtendsChain + where T10 : struct, IExtendsChain + where T11 : struct, IExtendsChain + where T12 : struct, IExtendsChain + where T13 : struct, IExtendsChain + where T14 : struct, IExtendsChain + where T15 : struct, IExtendsChain + => chain.TruncateAny(out item15); + + /// + /// Creates a new with 15 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// Type of Item 2. + /// Type of Item 3. + /// Type of Item 4. + /// Type of Item 5. + /// Type of Item 6. + /// Type of Item 7. + /// Type of Item 8. + /// Type of Item 9. + /// Type of Item 10. + /// Type of Item 11. + /// Type of Item 12. + /// Type of Item 13. + /// Type of Item 14. + /// Type of Item 15. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. /// - public ManagedChain Truncate(out T4 item4) - { - item4 = Item4; - - var newSize = MemorySize - Item4Size; + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T15 item15) + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + where T15 : struct, IChainable + { + // Retrieve last item. + item15 = chain.Item15; + + var newSize = ManagedChain.MemorySize - ManagedChain.Item15Size; var newHeadPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = null; - return new ManagedChain(newHeadPtr); - } - - /// - /// Creates a new with 6 items, by appending to - /// the end of this chain. - /// - /// Item 5. - /// Type of Item 5 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T5 item5 = default) - where T5: struct, IExtendsChain - { - return new ManagedChain(this, item5); - } - - /// - public override IEnumerator GetEnumerator() - { - yield return Head; - yield return Item1; - yield return Item2; - yield return Item3; - yield return Item4; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item2Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item3Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item4Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item5Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item6Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item7Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item8Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item9Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item10Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item11Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item12Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item13Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item14Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain.Item14Offset))->PNext = null; + return new ManagedChain(newHeadPtr); } - /// - public override int Count => 5; - - /// - public override IChainable this[int index] - => index switch - { - 0 => Head, - 1 => Item1, - 2 => Item2, - 3 => Item3, - 4 => Item4, - _ => throw new IndexOutOfRangeException() - }; - - /// - /// Deconstructs this chain. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4) - { - head = Head; - item1 = Item1; - item2 = Item2; - item3 = Item3; - item4 = Item4; - } - - /// - public override void Dispose() - { - var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); - if (headPtr == (nint)0) { - return; - } - - // Destroy all structures - Marshal.DestroyStructure(headPtr); - Marshal.DestroyStructure(headPtr + Item1Offset); - Marshal.DestroyStructure(headPtr + Item2Offset); - Marshal.DestroyStructure(headPtr + Item3Offset); - Marshal.DestroyStructure(headPtr + Item4Offset); - - // Free memory block - Marshal.FreeHGlobal(headPtr); - } } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type -/// Type of Item 1. -/// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable { /// - /// Gets the size (in bytes) of the head structure. - /// - public static readonly int HeadSize = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item1Offset = HeadSize; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item1Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item2Offset = Item1Offset + Item1Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item2Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item3Offset = Item2Offset + Item2Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item3Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item4Offset = Item3Offset + Item3Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item4Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . + /// Gets the size (in bytes) of the default structure header. /// - public static readonly int Item5Offset = Item4Offset + Item4Size; + public static readonly int HeaderSize = Marshal.SizeOf(); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets the size (in bytes) of the head structure. /// - public static readonly int Item5Size = Marshal.SizeOf(); + public static readonly int HeadSize = Marshal.SizeOf(); /// /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public static readonly int MemorySize = Item5Offset + Item5Size; - + public static readonly int MemorySize = HeadSize; + + /// + public override int Size => MemorySize; + private nint _headPtr; - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. @@ -2968,122 +10277,17 @@ public TChain Head set { value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set - { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef(Item4Ptr); - set - { - value.StructureType(); - var ptr = Item4Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef(Item5Ptr); - set - { - value.StructureType(); - var ptr = Item5Ptr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); + Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; } } /// - /// Creates a new with 6 items from an existing memory block. + /// Creates a new with 1 items from an existing memory block. /// - /// The pointer to the head of the chain.. + /// The pointer to the head of the chain. /// /// Callers are responsible for ensuring the size of the memory is correct. /// @@ -3093,267 +10297,216 @@ internal ManagedChain(nint headPtr) } /// - /// Creates a new with 6 items. + /// Creates a new with 1 items. /// /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + internal ManagedChain(TChain head = default) : this(Marshal.AllocHGlobal(MemorySize)) { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - Item5Ptr->PNext = null; + HeadPtr->PNext = null; } - /// - /// Creates a new with 6 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) + /// + public override IEnumerator GetEnumerator() { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; + yield return Head; + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + public override int Count => 1; - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 6"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; } - Marshal.StructureToPtr(item1, (nint) newPtr, false); + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 6"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(")"); + return sb.ToString(); + } - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 6"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + public void Deconstruct(out TChain head) + { + head = Head; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; } - Marshal.StructureToPtr(item3, (nint) newPtr, false); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + // Destroy all structures + Marshal.DestroyStructure(headPtr); - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 6"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable +{ + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 6"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 6"); - existingPtr->PNext = null; - } - item5 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item5, (nint) newPtr, false); + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); - // Create string of errors - errors = errorBuilder.ToString().Trim(); - } + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; /// - /// Creates a new with 6 by copying this chain. + /// Gets the size (in bytes) of the Item 1. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() - { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - return new ManagedChain(newHeadPtr); - } + public static readonly int Item1Size = Marshal.SizeOf(); /// - /// Creates a new with 6 items, by appending - /// to the end of this chain. + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - /// The chain to append to. - /// Item 5. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T5 item5 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item5Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + public static readonly int MemorySize = Item1Offset + Item1Size; - // Append item 5 - item5.StructureType(); - Marshal.StructureToPtr(item5, _headPtr + previousSize, false); + /// + public override int Size => MemorySize; - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; + private nint _headPtr; + + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((BaseInStructure*) _headPtr); + set + { + value.StructureType(); + var ptr = (BaseInStructure*) _headPtr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 5 items, by removing the last item - /// from this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 { - return Truncate(out var _); + get => Unsafe.AsRef(Item1Ptr); + set + { + value.StructureType(); + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 5 items, by removing - /// from the end of this chain. + /// Creates a new with 2 items from an existing memory block. /// + /// The pointer to the head of the chain. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Callers are responsible for ensuring the size of the memory is correct. /// - public ManagedChain Truncate(out T5 item5) + internal ManagedChain(nint headPtr) { - item5 = Item5; - - var newSize = MemorySize - Item5Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = null; - return new ManagedChain(newHeadPtr); + _headPtr = headPtr; } /// - /// Creates a new with 7 items, by appending to - /// the end of this chain. + /// Creates a new with 2 items. /// - /// Item 6. - /// Type of Item 6 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T6 item6 = default) - where T6: struct, IExtendsChain + /// The head of the chain. + /// Item 1. + internal ManagedChain(TChain head = default, T1 item1 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - return new ManagedChain(this, item6); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + Item1Ptr->PNext = null; } /// @@ -3361,14 +10514,10 @@ public override IEnumerator GetEnumerator() { yield return Head; yield return Item1; - yield return Item2; - yield return Item3; - yield return Item4; - yield return Item5; } /// - public override int Count => 6; + public override int Count => 2; /// public override IChainable this[int index] @@ -3376,30 +10525,79 @@ public override IChainable this[int index] { 0 => Head, 1 => Item1, - 2 => Item2, - 3 => Item3, - 4 => Item4, - 5 => Item5, _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// /// The head of the chain. /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5) + public void Deconstruct(out TChain head, out T1 item1) { head = Head; item1 = Item1; - item2 = Item2; - item3 = Item3; - item4 = Item4; - item5 = Item5; } /// @@ -3413,10 +10611,6 @@ public override void Dispose() // Destroy all structures Marshal.DestroyStructure(headPtr); Marshal.DestroyStructure(headPtr + Item1Offset); - Marshal.DestroyStructure(headPtr + Item2Offset); - Marshal.DestroyStructure(headPtr + Item3Offset); - Marshal.DestroyStructure(headPtr + Item4Offset); - Marshal.DestroyStructure(headPtr + Item5Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -3424,24 +10618,21 @@ public override void Dispose() } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. /// Type of Item 2. -/// Type of Item 3. -/// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -3467,57 +10658,18 @@ public unsafe class ManagedChain : ManagedChain /// public static readonly int Item2Size = Marshal.SizeOf(); - /// - /// Gets the offset to the start of . - /// - public static readonly int Item3Offset = Item2Offset + Item2Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item3Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item4Offset = Item3Offset + Item3Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item4Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item5Offset = Item4Offset + Item4Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item5Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item6Offset = Item5Offset + Item5Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item6Size = Marshal.SizeOf(); - /// /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public static readonly int MemorySize = Item6Offset + Item6Size; - + public static readonly int MemorySize = Item2Offset + Item2Size; + + /// + public override int Size => MemorySize; + private nint _headPtr; - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. @@ -3578,22 +10730,240 @@ public T2 Item2 } /// - /// Gets a pointer to the second item in the chain. + /// Creates a new with 3 items from an existing memory block. /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); + /// The pointer to the head of the chain. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } /// - /// Gets or sets item #3 in the chain. + /// Creates a new with 3 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default) + : this(Marshal.AllocHGlobal(MemorySize)) + { + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + Item2Ptr->PNext = null; + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + } + + /// + public override int Count => 3; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, + 1 => Item1, + 2 => Item2, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(")"); + return sb.ToString(); + } + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2) + { + head = Head; + item1 = Item1; + item2 = Item2; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable +{ + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item3Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item3Offset + Item3Size; + + /// + public override int Size => MemorySize; + + private nint _headPtr; + + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + + /// + /// Gets or sets the head of the chain. /// - public T3 Item3 + public TChain Head { - get => Unsafe.AsRef(Item3Ptr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = Item3Ptr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); + Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; } } @@ -3601,18 +10971,18 @@ public T3 Item3 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// - /// Gets or sets item #4 in the chain. + /// Gets or sets item #1 in the chain. /// - public T4 Item4 + public T1 Item1 { - get => Unsafe.AsRef(Item4Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var ptr = Item4Ptr; + var ptr = Item1Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -3622,18 +10992,18 @@ public T4 Item4 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// - /// Gets or sets item #5 in the chain. + /// Gets or sets item #2 in the chain. /// - public T5 Item5 + public T2 Item2 { - get => Unsafe.AsRef(Item5Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var ptr = Item5Ptr; + var ptr = Item2Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -3643,18 +11013,18 @@ public T5 Item5 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// - /// Gets or sets item #6 in the chain. + /// Gets or sets item #3 in the chain. /// - public T6 Item6 + public T3 Item3 { - get => Unsafe.AsRef(Item6Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var ptr = Item6Ptr; + var ptr = Item3Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -3662,9 +11032,9 @@ public T6 Item6 } /// - /// Creates a new with 7 items from an existing memory block. + /// Creates a new with 4 items from an existing memory block. /// - /// The pointer to the head of the chain.. + /// The pointer to the head of the chain. /// /// Callers are responsible for ensuring the size of the memory is correct. /// @@ -3674,21 +11044,18 @@ internal ManagedChain(nint headPtr) } /// - /// Creates a new with 7 items. + /// Creates a new with 4 items. /// /// The head of the chain. /// Item 1. /// Item 2. /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default) : this(Marshal.AllocHGlobal(MemorySize)) { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; + var itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -3700,270 +11067,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul item3.StructureType(); Marshal.StructureToPtr(item3, (nint)itemPtr, false); Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - itemPtr = Item6Ptr; - item6.StructureType(); - Marshal.StructureToPtr(item6, (nint)itemPtr, false); - Item5Ptr->PNext = itemPtr; - Item6Ptr->PNext = null; - } - - /// - /// Creates a new with 7 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 7"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 7"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 7"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 7"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 7"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item5, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 7"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 7"); - existingPtr->PNext = null; - } - item6 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item6, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - } - - /// - /// Creates a new with 7 by copying this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() - { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - return new ManagedChain(newHeadPtr); - } - - /// - /// Creates a new with 7 items, by appending - /// to the end of this chain. - /// - /// The chain to append to. - /// Item 6. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T6 item6 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item6Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 6 - item6.StructureType(); - Marshal.StructureToPtr(item6, _headPtr + previousSize, false); - - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; - } - - /// - /// Creates a new with 6 items, by removing the last item - /// from this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() - { - return Truncate(out var _); - } - - /// - /// Creates a new with 6 items, by removing - /// from the end of this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate(out T6 item6) - { - item6 = Item6; - - var newSize = MemorySize - Item6Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = null; - return new ManagedChain(newHeadPtr); - } - - /// - /// Creates a new with 8 items, by appending to - /// the end of this chain. - /// - /// Item 7. - /// Type of Item 7 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T7 item7 = default) - where T7: struct, IExtendsChain - { - return new ManagedChain(this, item7); + Item3Ptr->PNext = null; } /// @@ -3973,13 +11077,10 @@ public override IEnumerator GetEnumerator() yield return Item1; yield return Item2; yield return Item3; - yield return Item4; - yield return Item5; - yield return Item6; } /// - public override int Count => 7; + public override int Count => 4; /// public override IChainable this[int index] @@ -3989,12 +11090,90 @@ public override IChainable this[int index] 1 => Item1, 2 => Item2, 3 => Item3, - 4 => Item4, - 5 => Item5, - 6 => Item6, _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// @@ -4002,18 +11181,12 @@ public override IChainable this[int index] /// Item 1. /// Item 2. /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6) + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3) { head = Head; item1 = Item1; item2 = Item2; item3 = Item3; - item4 = Item4; - item5 = Item5; - item6 = Item6; } /// @@ -4029,9 +11202,6 @@ public override void Dispose() Marshal.DestroyStructure(headPtr + Item1Offset); Marshal.DestroyStructure(headPtr + Item2Offset); Marshal.DestroyStructure(headPtr + Item3Offset); - Marshal.DestroyStructure(headPtr + Item4Offset); - Marshal.DestroyStructure(headPtr + Item5Offset); - Marshal.DestroyStructure(headPtr + Item6Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -4039,26 +11209,25 @@ public override void Dispose() } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. /// Type of Item 2. /// Type of Item 3. /// Type of Item 4. -/// Type of Item 5. -/// Type of Item 6. -/// Type of Item 7. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -4104,47 +11273,18 @@ public unsafe class ManagedChain : ManagedCh /// public static readonly int Item4Size = Marshal.SizeOf(); - /// - /// Gets the offset to the start of . - /// - public static readonly int Item5Offset = Item4Offset + Item4Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item5Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item6Offset = Item5Offset + Item5Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item6Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item7Offset = Item6Offset + Item6Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item7Size = Marshal.SizeOf(); - /// /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public static readonly int MemorySize = Item7Offset + Item7Size; - + public static readonly int MemorySize = Item4Offset + Item4Size; + + /// + public override int Size => MemorySize; + private nint _headPtr; - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. @@ -4210,80 +11350,341 @@ public T2 Item2 public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// - /// Gets or sets item #3 in the chain. + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef(Item3Ptr); + set + { + value.StructureType(); + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); + + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef(Item4Ptr); + set + { + value.StructureType(); + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Creates a new with 5 items from an existing memory block. + /// + /// The pointer to the head of the chain. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + + /// + /// Creates a new with 5 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default) + : this(Marshal.AllocHGlobal(MemorySize)) + { + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + Item4Ptr->PNext = null; + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + } + + /// + public override int Count => 5; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, + 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(")"); + return sb.ToString(); + } + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable +{ + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item2Offset = Item1Offset + Item1Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; + + /// + /// Gets the size (in bytes) of the Item 1. /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item3Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); + public static readonly int Item4Offset = Item3Offset + Item3Size; /// - /// Gets or sets item #4 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T4 Item4 - { - get => Unsafe.AsRef(Item4Ptr); - set - { - value.StructureType(); - var ptr = Item4Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item4Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); + public static readonly int Item5Offset = Item4Offset + Item4Size; /// - /// Gets or sets item #5 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T5 Item5 - { - get => Unsafe.AsRef(Item5Ptr); - set - { - value.StructureType(); - var ptr = Item5Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item5Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); + public static readonly int MemorySize = Item5Offset + Item5Size; + + /// + public override int Size => MemorySize; + + private nint _headPtr; + + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// - /// Gets or sets item #6 in the chain. + /// Gets or sets the head of the chain. /// - public T6 Item6 + public TChain Head { - get => Unsafe.AsRef(Item6Ptr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = Item6Ptr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); + Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; } } @@ -4291,356 +11692,155 @@ public T6 Item6 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// - /// Gets or sets item #7 in the chain. + /// Gets or sets item #1 in the chain. /// - public T7 Item7 + public T1 Item1 { - get => Unsafe.AsRef(Item7Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var ptr = Item7Ptr; + var ptr = Item1Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; } - } - - /// - /// Creates a new with 8 items from an existing memory block. - /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } - - /// - /// Creates a new with 8 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - itemPtr = Item6Ptr; - item6.StructureType(); - Marshal.StructureToPtr(item6, (nint)itemPtr, false); - Item5Ptr->PNext = itemPtr; - itemPtr = Item7Ptr; - item7.StructureType(); - Marshal.StructureToPtr(item7, (nint)itemPtr, false); - Item6Ptr->PNext = itemPtr; - Item7Ptr->PNext = null; - } - - /// - /// Creates a new with 8 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 8"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 8"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 8"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 8"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 8"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item5, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 8"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item6 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item6, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - T7 item7 = default; - expectedStructureType = item7.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 8"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 8"); - existingPtr->PNext = null; - } - item7 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef(Item2Ptr); + set + { + value.StructureType(); + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item7, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); } /// - /// Creates a new with 8 by copying this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - return new ManagedChain(newHeadPtr); + get => Unsafe.AsRef(Item3Ptr); + set + { + value.StructureType(); + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 8 items, by appending - /// to the end of this chain. + /// Gets a pointer to the second item in the chain. /// - /// The chain to append to. - /// Item 7. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T7 item7 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item7Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 7 - item7.StructureType(); - Marshal.StructureToPtr(item7, _headPtr + previousSize, false); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef(Item4Ptr); + set + { + value.StructureType(); + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 7 items, by removing the last item - /// from this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 { - return Truncate(out var _); + get => Unsafe.AsRef(Item5Ptr); + set + { + value.StructureType(); + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 7 items, by removing - /// from the end of this chain. + /// Creates a new with 6 items from an existing memory block. /// + /// The pointer to the head of the chain. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Callers are responsible for ensuring the size of the memory is correct. /// - public ManagedChain Truncate(out T7 item7) + internal ManagedChain(nint headPtr) { - item7 = Item7; - - var newSize = MemorySize - Item7Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = null; - return new ManagedChain(newHeadPtr); + _headPtr = headPtr; } /// - /// Creates a new with 9 items, by appending to - /// the end of this chain. + /// Creates a new with 6 items. /// - /// Item 8. - /// Type of Item 8 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T8 item8 = default) - where T8: struct, IExtendsChain + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - return new ManagedChain(this, item8); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + Item5Ptr->PNext = null; } /// @@ -4652,12 +11852,10 @@ public override IEnumerator GetEnumerator() yield return Item3; yield return Item4; yield return Item5; - yield return Item6; - yield return Item7; } /// - public override int Count => 8; + public override int Count => 6; /// public override IChainable this[int index] @@ -4669,11 +11867,110 @@ public override IChainable this[int index] 3 => Item3, 4 => Item4, 5 => Item5, - 6 => Item6, - 7 => Item7, _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// @@ -4683,9 +11980,7 @@ public override IChainable this[int index] /// Item 3. /// Item 4. /// Item 5. - /// Item 6. - /// Item 7. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7) + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5) { head = Head; item1 = Item1; @@ -4693,8 +11988,6 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item item3 = Item3; item4 = Item4; item5 = Item5; - item6 = Item6; - item7 = Item7; } /// @@ -4712,8 +12005,6 @@ public override void Dispose() Marshal.DestroyStructure(headPtr + Item3Offset); Marshal.DestroyStructure(headPtr + Item4Offset); Marshal.DestroyStructure(headPtr + Item5Offset); - Marshal.DestroyStructure(headPtr + Item6Offset); - Marshal.DestroyStructure(headPtr + Item7Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -4721,7 +12012,7 @@ public override void Dispose() } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. @@ -4730,19 +12021,20 @@ public override void Dispose() /// Type of Item 4. /// Type of Item 5. /// Type of Item 6. -/// Type of Item 7. -/// Type of Item 8. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -4808,37 +12100,18 @@ public unsafe class ManagedChain : Manag /// public static readonly int Item6Size = Marshal.SizeOf(); - /// - /// Gets the offset to the start of . - /// - public static readonly int Item7Offset = Item6Offset + Item6Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item7Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item8Offset = Item7Offset + Item7Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item8Size = Marshal.SizeOf(); - /// /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public static readonly int MemorySize = Item8Offset + Item8Size; - + public static readonly int MemorySize = Item6Offset + Item6Size; + + /// + public override int Size => MemorySize; + private nint _headPtr; - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. @@ -4983,51 +12256,9 @@ public T6 Item6 } /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef(Item7Ptr); - set - { - value.StructureType(); - var ptr = Item7Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef(Item8Ptr); - set - { - value.StructureType(); - var ptr = Item8Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Creates a new with 9 items from an existing memory block. + /// Creates a new with 7 items from an existing memory block. /// - /// The pointer to the head of the chain.. + /// The pointer to the head of the chain. /// /// Callers are responsible for ensuring the size of the memory is correct. /// @@ -5037,7 +12268,7 @@ internal ManagedChain(nint headPtr) } /// - /// Creates a new with 9 items. + /// Creates a new with 7 items. /// /// The head of the chain. /// Item 1. @@ -5046,14 +12277,12 @@ internal ManagedChain(nint headPtr) /// Item 4. /// Item 5. /// Item 6. - /// Item 7. - /// Item 8. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default) : this(Marshal.AllocHGlobal(MemorySize)) { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; + var itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; @@ -5077,314 +12306,7 @@ public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = defaul item6.StructureType(); Marshal.StructureToPtr(item6, (nint)itemPtr, false); Item5Ptr->PNext = itemPtr; - itemPtr = Item7Ptr; - item7.StructureType(); - Marshal.StructureToPtr(item7, (nint)itemPtr, false); - Item6Ptr->PNext = itemPtr; - itemPtr = Item8Ptr; - item8.StructureType(); - Marshal.StructureToPtr(item8, (nint)itemPtr, false); - Item7Ptr->PNext = itemPtr; - Item8Ptr->PNext = null; - } - - /// - /// Creates a new with 9 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 9"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 9"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 9"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 9"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 9"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item5, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 9"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item6 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item6, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T7 item7 = default; - expectedStructureType = item7.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 9"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item7 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item7, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T8 item8 = default; - expectedStructureType = item8.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 9"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 9"); - existingPtr->PNext = null; - } - item8 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item8, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); - } - - /// - /// Creates a new with 9 by copying this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() - { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - return new ManagedChain(newHeadPtr); - } - - /// - /// Creates a new with 9 items, by appending - /// to the end of this chain. - /// - /// The chain to append to. - /// Item 8. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T8 item8 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item8Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 8 - item8.StructureType(); - Marshal.StructureToPtr(item8, _headPtr + previousSize, false); - - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); - ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; - } - - /// - /// Creates a new with 8 items, by removing the last item - /// from this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() - { - return Truncate(out var _); - } - - /// - /// Creates a new with 8 items, by removing - /// from the end of this chain. - /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate(out T8 item8) - { - item8 = Item8; - - var newSize = MemorySize - Item8Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = null; - return new ManagedChain(newHeadPtr); - } - - /// - /// Creates a new with 10 items, by appending to - /// the end of this chain. - /// - /// Item 9. - /// Type of Item 9 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T9 item9 = default) - where T9: struct, IExtendsChain - { - return new ManagedChain(this, item9); + Item6Ptr->PNext = null; } /// @@ -5397,12 +12319,10 @@ public override IEnumerator GetEnumerator() yield return Item4; yield return Item5; yield return Item6; - yield return Item7; - yield return Item8; } /// - public override int Count => 9; + public override int Count => 7; /// public override IChainable this[int index] @@ -5415,11 +12335,120 @@ public override IChainable this[int index] 4 => Item4, 5 => Item5, 6 => Item6, - 7 => Item7, - 8 => Item8, _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// @@ -5429,10 +12458,8 @@ public override IChainable this[int index] /// Item 3. /// Item 4. /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8) + /// Item 6. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6) { head = Head; item1 = Item1; @@ -5441,8 +12468,6 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item item4 = Item4; item5 = Item5; item6 = Item6; - item7 = Item7; - item8 = Item8; } /// @@ -5461,8 +12486,6 @@ public override void Dispose() Marshal.DestroyStructure(headPtr + Item4Offset); Marshal.DestroyStructure(headPtr + Item5Offset); Marshal.DestroyStructure(headPtr + Item6Offset); - Marshal.DestroyStructure(headPtr + Item7Offset); - Marshal.DestroyStructure(headPtr + Item8Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -5470,7 +12493,7 @@ public override void Dispose() } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. @@ -5480,20 +12503,21 @@ public override void Dispose() /// Type of Item 5. /// Type of Item 6. /// Type of Item 7. -/// Type of Item 8. -/// Type of Item 9. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -5569,37 +12593,18 @@ public unsafe class ManagedChain : M /// public static readonly int Item7Size = Marshal.SizeOf(); - /// - /// Gets the offset to the start of . - /// - public static readonly int Item8Offset = Item7Offset + Item7Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item8Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item9Offset = Item8Offset + Item8Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item9Size = Marshal.SizeOf(); - /// /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public static readonly int MemorySize = Item9Offset + Item9Size; - + public static readonly int MemorySize = Item7Offset + Item7Size; + + /// + public override int Size => MemorySize; + private nint _headPtr; - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. @@ -5723,479 +12728,676 @@ public T5 Item5 } /// - /// Gets a pointer to the second item in the chain. + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef(Item6Ptr); + set + { + value.StructureType(); + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef(Item7Ptr); + set + { + value.StructureType(); + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Creates a new with 8 items from an existing memory block. + /// + /// The pointer to the head of the chain. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + + /// + /// Creates a new with 8 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default) + : this(Marshal.AllocHGlobal(MemorySize)) + { + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; + item6.StructureType(); + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; + item7.StructureType(); + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + Item7Ptr->PNext = null; + } + + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + } + + /// + public override int Count => 8; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, + 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + _ => throw new IndexOutOfRangeException() + }; + + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(")"); + return sb.ToString(); + } + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; + } + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + + // Free memory block + Marshal.FreeHGlobal(headPtr); + } +} + +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable +{ + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item1Offset = HeadSize; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item1Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . /// - public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); + public static readonly int Item2Offset = Item1Offset + Item1Size; /// - /// Gets or sets item #6 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T6 Item6 - { - get => Unsafe.AsRef(Item6Ptr); - set - { - value.StructureType(); - var ptr = Item6Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item2Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); + public static readonly int Item3Offset = Item2Offset + Item2Size; /// - /// Gets or sets item #7 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T7 Item7 - { - get => Unsafe.AsRef(Item7Ptr); - set - { - value.StructureType(); - var ptr = Item7Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item3Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); + public static readonly int Item4Offset = Item3Offset + Item3Size; /// - /// Gets or sets item #8 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T8 Item8 - { - get => Unsafe.AsRef(Item8Ptr); - set - { - value.StructureType(); - var ptr = Item8Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item4Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); + public static readonly int Item5Offset = Item4Offset + Item4Size; /// - /// Gets or sets item #9 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T9 Item9 - { - get => Unsafe.AsRef(Item9Ptr); - set - { - value.StructureType(); - var ptr = Item9Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item5Size = Marshal.SizeOf(); /// - /// Creates a new with 10 items from an existing memory block. + /// Gets the offset to the start of . /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } + public static readonly int Item6Offset = Item5Offset + Item5Size; /// - /// Creates a new with 10 items. + /// Gets the size (in bytes) of the Item 1. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - itemPtr = Item6Ptr; - item6.StructureType(); - Marshal.StructureToPtr(item6, (nint)itemPtr, false); - Item5Ptr->PNext = itemPtr; - itemPtr = Item7Ptr; - item7.StructureType(); - Marshal.StructureToPtr(item7, (nint)itemPtr, false); - Item6Ptr->PNext = itemPtr; - itemPtr = Item8Ptr; - item8.StructureType(); - Marshal.StructureToPtr(item8, (nint)itemPtr, false); - Item7Ptr->PNext = itemPtr; - itemPtr = Item9Ptr; - item9.StructureType(); - Marshal.StructureToPtr(item9, (nint)itemPtr, false); - Item8Ptr->PNext = itemPtr; - Item9Ptr->PNext = null; - } + public static readonly int Item6Size = Marshal.SizeOf(); /// - /// Creates a new with 10 items from an existing unmanaged chain. + /// Gets the offset to the start of . /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 10"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + public static readonly int Item7Offset = Item6Offset + Item6Size; - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 10"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 10"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item8Offset + Item8Size; + + /// + public override int Size => MemorySize; - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 10"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); + private nint _headPtr; - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 10"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((BaseInStructure*) _headPtr); + set + { + value.StructureType(); + var ptr = (BaseInStructure*) _headPtr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item5, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 10"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item6 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef(Item1Ptr); + set + { + value.StructureType(); + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item6, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - T7 item7 = default; - expectedStructureType = item7.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 10"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item7 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef(Item2Ptr); + set + { + value.StructureType(); + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item7, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - T8 item8 = default; - expectedStructureType = item8.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 10"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item8 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef(Item3Ptr); + set + { + value.StructureType(); + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item8, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - T9 item9 = default; - expectedStructureType = item9.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 10"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 10"); - existingPtr->PNext = null; - } - item9 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef(Item4Ptr); + set + { + value.StructureType(); + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item9, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); } /// - /// Creates a new with 10 by copying this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); + + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - return new ManagedChain(newHeadPtr); + get => Unsafe.AsRef(Item5Ptr); + set + { + value.StructureType(); + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 10 items, by appending - /// to the end of this chain. + /// Gets a pointer to the second item in the chain. /// - /// The chain to append to. - /// Item 9. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T9 item9 = default) - : this(Marshal.AllocHGlobal(MemorySize)) + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 { - var previousSize = MemorySize - Item9Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 9 - item9.StructureType(); - Marshal.StructureToPtr(item9, _headPtr + previousSize, false); + get => Unsafe.AsRef(Item6Ptr); + set + { + value.StructureType(); + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); - ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); - ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef(Item7Ptr); + set + { + value.StructureType(); + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 9 items, by removing the last item - /// from this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 { - return Truncate(out var _); + get => Unsafe.AsRef(Item8Ptr); + set + { + value.StructureType(); + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 9 items, by removing - /// from the end of this chain. + /// Creates a new with 9 items from an existing memory block. /// + /// The pointer to the head of the chain. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Callers are responsible for ensuring the size of the memory is correct. /// - public ManagedChain Truncate(out T9 item9) + internal ManagedChain(nint headPtr) { - item9 = Item9; - - var newSize = MemorySize - Item9Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = null; - return new ManagedChain(newHeadPtr); + _headPtr = headPtr; } /// - /// Creates a new with 11 items, by appending to - /// the end of this chain. + /// Creates a new with 9 items. /// - /// Item 10. - /// Type of Item 10 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T10 item10 = default) - where T10: struct, IExtendsChain + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - return new ManagedChain(this, item10); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; + item6.StructureType(); + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; + item7.StructureType(); + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; + item8.StructureType(); + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + Item8Ptr->PNext = null; } /// @@ -6210,11 +13412,10 @@ public override IEnumerator GetEnumerator() yield return Item6; yield return Item7; yield return Item8; - yield return Item9; } /// - public override int Count => 10; + public override int Count => 9; /// public override IChainable this[int index] @@ -6229,10 +13430,140 @@ public override IChainable this[int index] 6 => Item6, 7 => Item7, 8 => Item8, - 9 => Item9, _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(", "); + sb.Append((object) Item8); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// @@ -6245,8 +13576,7 @@ public override IChainable this[int index] /// Item 6. /// Item 7. /// Item 8. - /// Item 9. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9) + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8) { head = Head; item1 = Item1; @@ -6257,7 +13587,6 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item item6 = Item6; item7 = Item7; item8 = Item8; - item9 = Item9; } /// @@ -6278,7 +13607,6 @@ public override void Dispose() Marshal.DestroyStructure(headPtr + Item6Offset); Marshal.DestroyStructure(headPtr + Item7Offset); Marshal.DestroyStructure(headPtr + Item8Offset); - Marshal.DestroyStructure(headPtr + Item9Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -6286,7 +13614,7 @@ public override void Dispose() } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. @@ -6298,20 +13626,23 @@ public override void Dispose() /// Type of Item 7. /// Type of Item 8. /// Type of Item 9. -/// Type of Item 10. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -6380,700 +13711,318 @@ public unsafe class ManagedChain /// Gets the offset to the start of . /// - public static readonly int Item7Offset = Item6Offset + Item6Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item7Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item8Offset = Item7Offset + Item7Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item8Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item9Offset = Item8Offset + Item8Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item9Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item10Offset = Item9Offset + Item9Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item10Size = Marshal.SizeOf(); - - /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. - /// - public static readonly int MemorySize = Item10Offset + Item10Size; - - private nint _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set - { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef(Item4Ptr); - set - { - value.StructureType(); - var ptr = Item4Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef(Item5Ptr); - set - { - value.StructureType(); - var ptr = Item5Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef(Item6Ptr); - set - { - value.StructureType(); - var ptr = Item6Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); + public static readonly int Item7Offset = Item6Offset + Item6Size; /// - /// Gets or sets item #7 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T7 Item7 - { - get => Unsafe.AsRef(Item7Ptr); - set - { - value.StructureType(); - var ptr = Item7Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item7Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); + public static readonly int Item8Offset = Item7Offset + Item7Size; /// - /// Gets or sets item #8 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T8 Item8 - { - get => Unsafe.AsRef(Item8Ptr); - set - { - value.StructureType(); - var ptr = Item8Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item8Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); + public static readonly int Item9Offset = Item8Offset + Item8Size; /// - /// Gets or sets item #9 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T9 Item9 - { - get => Unsafe.AsRef(Item9Ptr); - set - { - value.StructureType(); - var ptr = Item9Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item9Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); + public static readonly int MemorySize = Item9Offset + Item9Size; + + /// + public override int Size => MemorySize; + + private nint _headPtr; + + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// - /// Gets or sets item #10 in the chain. + /// Gets or sets the head of the chain. /// - public T10 Item10 + public TChain Head { - get => Unsafe.AsRef(Item10Ptr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = Item10Ptr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); + Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; } } /// - /// Creates a new with 11 items from an existing memory block. - /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } - - /// - /// Creates a new with 11 items. + /// Gets a pointer to the second item in the chain. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - itemPtr = Item6Ptr; - item6.StructureType(); - Marshal.StructureToPtr(item6, (nint)itemPtr, false); - Item5Ptr->PNext = itemPtr; - itemPtr = Item7Ptr; - item7.StructureType(); - Marshal.StructureToPtr(item7, (nint)itemPtr, false); - Item6Ptr->PNext = itemPtr; - itemPtr = Item8Ptr; - item8.StructureType(); - Marshal.StructureToPtr(item8, (nint)itemPtr, false); - Item7Ptr->PNext = itemPtr; - itemPtr = Item9Ptr; - item9.StructureType(); - Marshal.StructureToPtr(item9, (nint)itemPtr, false); - Item8Ptr->PNext = itemPtr; - itemPtr = Item10Ptr; - item10.StructureType(); - Marshal.StructureToPtr(item10, (nint)itemPtr, false); - Item9Ptr->PNext = itemPtr; - Item10Ptr->PNext = null; - } + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// - /// Creates a new with 11 items from an existing unmanaged chain. + /// Gets or sets item #1 in the chain. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) + public T1 Item1 { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item5, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item6 = Unsafe.AsRef(existingPtr); - } + get => Unsafe.AsRef(Item1Ptr); + set + { + value.StructureType(); + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item6, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - T7 item7 = default; - expectedStructureType = item7.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item7 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef(Item2Ptr); + set + { + value.StructureType(); + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item7, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - T8 item8 = default; - expectedStructureType = item8.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item8 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef(Item3Ptr); + set + { + value.StructureType(); + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item8, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - T9 item9 = default; - expectedStructureType = item9.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item9 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef(Item4Ptr); + set + { + value.StructureType(); + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item9, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - T10 item10 = default; - expectedStructureType = item10.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 11"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 11"); - existingPtr->PNext = null; - } - item10 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef(Item5Ptr); + set + { + value.StructureType(); + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item10, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); } /// - /// Creates a new with 11 by copying this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); + + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - return new ManagedChain(newHeadPtr); + get => Unsafe.AsRef(Item6Ptr); + set + { + value.StructureType(); + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 11 items, by appending - /// to the end of this chain. + /// Gets a pointer to the second item in the chain. /// - /// The chain to append to. - /// Item 10. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T10 item10 = default) - : this(Marshal.AllocHGlobal(MemorySize)) + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); + + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 { - var previousSize = MemorySize - Item10Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 10 - item10.StructureType(); - Marshal.StructureToPtr(item10, _headPtr + previousSize, false); + get => Unsafe.AsRef(Item7Ptr); + set + { + value.StructureType(); + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); - ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); - ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); - ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef(Item8Ptr); + set + { + value.StructureType(); + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 10 items, by removing the last item - /// from this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 { - return Truncate(out var _); + get => Unsafe.AsRef(Item9Ptr); + set + { + value.StructureType(); + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 10 items, by removing - /// from the end of this chain. + /// Creates a new with 10 items from an existing memory block. /// + /// The pointer to the head of the chain. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Callers are responsible for ensuring the size of the memory is correct. /// - public ManagedChain Truncate(out T10 item10) + internal ManagedChain(nint headPtr) { - item10 = Item10; - - var newSize = MemorySize - Item10Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = null; - return new ManagedChain(newHeadPtr); + _headPtr = headPtr; } /// - /// Creates a new with 12 items, by appending to - /// the end of this chain. + /// Creates a new with 10 items. /// - /// Item 11. - /// Type of Item 11 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T11 item11 = default) - where T11: struct, IExtendsChain + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - return new ManagedChain(this, item11); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; + item6.StructureType(); + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; + item7.StructureType(); + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; + item8.StructureType(); + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; + item9.StructureType(); + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + Item9Ptr->PNext = null; } /// @@ -7089,11 +14038,10 @@ public override IEnumerator GetEnumerator() yield return Item7; yield return Item8; yield return Item9; - yield return Item10; } /// - public override int Count => 11; + public override int Count => 10; /// public override IChainable this[int index] @@ -7109,10 +14057,150 @@ public override IChainable this[int index] 7 => Item7, 8 => Item8, 9 => Item9, - 10 => Item10, _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(", "); + sb.Append((object) Item8); + sb.Append(", "); + sb.Append((object) Item9); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// @@ -7126,8 +14214,7 @@ public override IChainable this[int index] /// Item 7. /// Item 8. /// Item 9. - /// Item 10. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10) + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9) { head = Head; item1 = Item1; @@ -7139,7 +14226,6 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item item7 = Item7; item8 = Item8; item9 = Item9; - item10 = Item10; } /// @@ -7161,7 +14247,6 @@ public override void Dispose() Marshal.DestroyStructure(headPtr + Item7Offset); Marshal.DestroyStructure(headPtr + Item8Offset); Marshal.DestroyStructure(headPtr + Item9Offset); - Marshal.DestroyStructure(headPtr + Item10Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -7169,7 +14254,7 @@ public override void Dispose() } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. @@ -7182,21 +14267,24 @@ public override void Dispose() /// Type of Item 8. /// Type of Item 9. /// Type of Item 10. -/// Type of Item 11. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -7302,27 +14390,18 @@ public unsafe class ManagedChain public static readonly int Item10Size = Marshal.SizeOf(); - /// - /// Gets the offset to the start of . - /// - public static readonly int Item11Offset = Item10Offset + Item10Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item11Size = Marshal.SizeOf(); - /// /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public static readonly int MemorySize = Item11Offset + Item11Size; - + public static readonly int MemorySize = Item10Offset + Item10Size; + + /// + public override int Size => MemorySize; + private nint _headPtr; - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. @@ -7335,175 +14414,7 @@ public TChain Head value.StructureType(); var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set - { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef(Item4Ptr); - set - { - value.StructureType(); - var ptr = Item4Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef(Item5Ptr); - set - { - value.StructureType(); - var ptr = Item5Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef(Item6Ptr); - set - { - value.StructureType(); - var ptr = Item6Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef(Item7Ptr); - set - { - value.StructureType(); - var ptr = Item7Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef(Item8Ptr); - set - { - value.StructureType(); - var ptr = Item8Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); + Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; } } @@ -7511,18 +14422,18 @@ public T8 Item8 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// - /// Gets or sets item #9 in the chain. + /// Gets or sets item #1 in the chain. /// - public T9 Item9 + public T1 Item1 { - get => Unsafe.AsRef(Item9Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var ptr = Item9Ptr; + var ptr = Item1Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -7532,18 +14443,18 @@ public T9 Item9 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// - /// Gets or sets item #10 in the chain. + /// Gets or sets item #2 in the chain. /// - public T10 Item10 + public T2 Item2 { - get => Unsafe.AsRef(Item10Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var ptr = Item10Ptr; + var ptr = Item2Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -7553,18 +14464,18 @@ public T10 Item10 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// - /// Gets or sets item #11 in the chain. + /// Gets or sets item #3 in the chain. /// - public T11 Item11 + public T3 Item3 { - get => Unsafe.AsRef(Item11Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var ptr = Item11Ptr; + var ptr = Item3Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -7572,453 +14483,224 @@ public T11 Item11 } /// - /// Creates a new with 12 items from an existing memory block. - /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } - - /// - /// Creates a new with 12 items. + /// Gets a pointer to the second item in the chain. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - itemPtr = Item6Ptr; - item6.StructureType(); - Marshal.StructureToPtr(item6, (nint)itemPtr, false); - Item5Ptr->PNext = itemPtr; - itemPtr = Item7Ptr; - item7.StructureType(); - Marshal.StructureToPtr(item7, (nint)itemPtr, false); - Item6Ptr->PNext = itemPtr; - itemPtr = Item8Ptr; - item8.StructureType(); - Marshal.StructureToPtr(item8, (nint)itemPtr, false); - Item7Ptr->PNext = itemPtr; - itemPtr = Item9Ptr; - item9.StructureType(); - Marshal.StructureToPtr(item9, (nint)itemPtr, false); - Item8Ptr->PNext = itemPtr; - itemPtr = Item10Ptr; - item10.StructureType(); - Marshal.StructureToPtr(item10, (nint)itemPtr, false); - Item9Ptr->PNext = itemPtr; - itemPtr = Item11Ptr; - item11.StructureType(); - Marshal.StructureToPtr(item11, (nint)itemPtr, false); - Item10Ptr->PNext = itemPtr; - Item11Ptr->PNext = null; - } + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// - /// Creates a new with 12 items from an existing unmanaged chain. + /// Gets or sets item #4 in the chain. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item5, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item6 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item6, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T7 item7 = default; - expectedStructureType = item7.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item7 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item7, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T8 item8 = default; - expectedStructureType = item8.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item8 = Unsafe.AsRef(existingPtr); - } + public T4 Item4 + { + get => Unsafe.AsRef(Item4Ptr); + set + { + value.StructureType(); + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item8, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - T9 item9 = default; - expectedStructureType = item9.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item9 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef(Item5Ptr); + set + { + value.StructureType(); + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item9, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); - T10 item10 = default; - expectedStructureType = item10.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item10 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef(Item6Ptr); + set + { + value.StructureType(); + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item10, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); - T11 item11 = default; - expectedStructureType = item11.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 12"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 12"); - existingPtr->PNext = null; - } - item11 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef(Item7Ptr); + set + { + value.StructureType(); + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item11, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); } /// - /// Creates a new with 12 by copying this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); + + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); - return new ManagedChain(newHeadPtr); + get => Unsafe.AsRef(Item8Ptr); + set + { + value.StructureType(); + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 12 items, by appending - /// to the end of this chain. + /// Gets a pointer to the second item in the chain. /// - /// The chain to append to. - /// Item 11. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T11 item11 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item11Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 11 - item11.StructureType(); - Marshal.StructureToPtr(item11, _headPtr + previousSize, false); + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); - ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); - ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); - ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); - ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef(Item9Ptr); + set + { + value.StructureType(); + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 11 items, by removing the last item - /// from this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 { - return Truncate(out var _); + get => Unsafe.AsRef(Item10Ptr); + set + { + value.StructureType(); + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 11 items, by removing - /// from the end of this chain. + /// Creates a new with 11 items from an existing memory block. /// + /// The pointer to the head of the chain. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Callers are responsible for ensuring the size of the memory is correct. /// - public ManagedChain Truncate(out T11 item11) + internal ManagedChain(nint headPtr) { - item11 = Item11; - - var newSize = MemorySize - Item11Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = null; - return new ManagedChain(newHeadPtr); + _headPtr = headPtr; } /// - /// Creates a new with 13 items, by appending to - /// the end of this chain. + /// Creates a new with 11 items. /// - /// Item 12. - /// Type of Item 12 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T12 item12 = default) - where T12: struct, IExtendsChain + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - return new ManagedChain(this, item12); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; + item6.StructureType(); + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; + item7.StructureType(); + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; + item8.StructureType(); + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; + item9.StructureType(); + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; + item10.StructureType(); + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + Item10Ptr->PNext = null; } /// @@ -8035,11 +14717,10 @@ public override IEnumerator GetEnumerator() yield return Item8; yield return Item9; yield return Item10; - yield return Item11; } /// - public override int Count => 12; + public override int Count => 11; /// public override IChainable this[int index] @@ -8056,10 +14737,160 @@ public override IChainable this[int index] 8 => Item8, 9 => Item9, 10 => Item10, - 11 => Item11, _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(", "); + sb.Append((object) Item8); + sb.Append(", "); + sb.Append((object) Item9); + sb.Append(", "); + sb.Append((object) Item10); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// @@ -8074,8 +14905,7 @@ public override IChainable this[int index] /// Item 8. /// Item 9. /// Item 10. - /// Item 11. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10, out T11 item11) + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10) { head = Head; item1 = Item1; @@ -8088,7 +14918,6 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item item8 = Item8; item9 = Item9; item10 = Item10; - item11 = Item11; } /// @@ -8111,7 +14940,6 @@ public override void Dispose() Marshal.DestroyStructure(headPtr + Item8Offset); Marshal.DestroyStructure(headPtr + Item9Offset); Marshal.DestroyStructure(headPtr + Item10Offset); - Marshal.DestroyStructure(headPtr + Item11Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -8119,7 +14947,7 @@ public override void Dispose() } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. @@ -8133,22 +14961,25 @@ public override void Dispose() /// Type of Item 9. /// Type of Item 10. /// Type of Item 11. -/// Type of Item 12. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -8257,257 +15088,38 @@ public unsafe class ManagedChain /// Gets the offset to the start of . /// - public static readonly int Item11Offset = Item10Offset + Item10Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item11Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item12Offset = Item11Offset + Item11Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item12Size = Marshal.SizeOf(); - - /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. - /// - public static readonly int MemorySize = Item12Offset + Item12Size; - - private nint _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); - - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set - { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef(Item4Ptr); - set - { - value.StructureType(); - var ptr = Item4Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef(Item5Ptr); - set - { - value.StructureType(); - var ptr = Item5Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef(Item6Ptr); - set - { - value.StructureType(); - var ptr = Item6Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef(Item7Ptr); - set - { - value.StructureType(); - var ptr = Item7Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef(Item8Ptr); - set - { - value.StructureType(); - var ptr = Item8Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); - - /// - /// Gets or sets item #9 in the chain. - /// - public T9 Item9 - { - get => Unsafe.AsRef(Item9Ptr); - set - { - value.StructureType(); - var ptr = Item9Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item11Offset = Item10Offset + Item10Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); + public static readonly int Item11Size = Marshal.SizeOf(); /// - /// Gets or sets item #10 in the chain. + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public T10 Item10 + public static readonly int MemorySize = Item11Offset + Item11Size; + + /// + public override int Size => MemorySize; + + private nint _headPtr; + + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head { - get => Unsafe.AsRef(Item10Ptr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = Item10Ptr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); + Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; } } @@ -8515,18 +15127,18 @@ public T10 Item10 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// - /// Gets or sets item #11 in the chain. + /// Gets or sets item #1 in the chain. /// - public T11 Item11 + public T1 Item1 { - get => Unsafe.AsRef(Item11Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var ptr = Item11Ptr; + var ptr = Item1Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -8536,18 +15148,18 @@ public T11 Item11 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// - /// Gets or sets item #12 in the chain. + /// Gets or sets item #2 in the chain. /// - public T12 Item12 + public T2 Item2 { - get => Unsafe.AsRef(Item12Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var ptr = Item12Ptr; + var ptr = Item2Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -8555,482 +15167,271 @@ public T12 Item12 } /// - /// Creates a new with 13 items from an existing memory block. - /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } - - /// - /// Creates a new with 13 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - itemPtr = Item6Ptr; - item6.StructureType(); - Marshal.StructureToPtr(item6, (nint)itemPtr, false); - Item5Ptr->PNext = itemPtr; - itemPtr = Item7Ptr; - item7.StructureType(); - Marshal.StructureToPtr(item7, (nint)itemPtr, false); - Item6Ptr->PNext = itemPtr; - itemPtr = Item8Ptr; - item8.StructureType(); - Marshal.StructureToPtr(item8, (nint)itemPtr, false); - Item7Ptr->PNext = itemPtr; - itemPtr = Item9Ptr; - item9.StructureType(); - Marshal.StructureToPtr(item9, (nint)itemPtr, false); - Item8Ptr->PNext = itemPtr; - itemPtr = Item10Ptr; - item10.StructureType(); - Marshal.StructureToPtr(item10, (nint)itemPtr, false); - Item9Ptr->PNext = itemPtr; - itemPtr = Item11Ptr; - item11.StructureType(); - Marshal.StructureToPtr(item11, (nint)itemPtr, false); - Item10Ptr->PNext = itemPtr; - itemPtr = Item12Ptr; - item12.StructureType(); - Marshal.StructureToPtr(item12, (nint)itemPtr, false); - Item11Ptr->PNext = itemPtr; - Item12Ptr->PNext = null; - } - - /// - /// Creates a new with 13 items from an existing unmanaged chain. + /// Gets a pointer to the second item in the chain. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item5, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item6 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item6, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - T7 item7 = default; - expectedStructureType = item7.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item7 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef(Item3Ptr); + set + { + value.StructureType(); + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item7, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - T8 item8 = default; - expectedStructureType = item8.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item8 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef(Item4Ptr); + set + { + value.StructureType(); + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item8, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - T9 item9 = default; - expectedStructureType = item9.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item9 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef(Item5Ptr); + set + { + value.StructureType(); + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item9, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); - T10 item10 = default; - expectedStructureType = item10.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item10 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef(Item6Ptr); + set + { + value.StructureType(); + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item10, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); - T11 item11 = default; - expectedStructureType = item11.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item11 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef(Item7Ptr); + set + { + value.StructureType(); + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item11, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item12Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); - T12 item12 = default; - expectedStructureType = item12.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 13"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 13; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 13"); - existingPtr->PNext = null; - } - item12 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef(Item8Ptr); + set + { + value.StructureType(); + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item12, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); } /// - /// Creates a new with 13 by copying this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); + + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); - ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); - return new ManagedChain(newHeadPtr); + get => Unsafe.AsRef(Item9Ptr); + set + { + value.StructureType(); + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 13 items, by appending - /// to the end of this chain. + /// Gets a pointer to the second item in the chain. /// - /// The chain to append to. - /// Item 12. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T12 item12 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item12Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 12 - item12.StructureType(); - Marshal.StructureToPtr(item12, _headPtr + previousSize, false); + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); - ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); - ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); - ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); - ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); - ((BaseInStructure*)(_headPtr + Item11Offset))->PNext = (BaseInStructure*) (_headPtr + Item12Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef(Item10Ptr); + set + { + value.StructureType(); + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 12 items, by removing the last item - /// from this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 { - return Truncate(out var _); + get => Unsafe.AsRef(Item11Ptr); + set + { + value.StructureType(); + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 12 items, by removing - /// from the end of this chain. + /// Creates a new with 12 items from an existing memory block. /// + /// The pointer to the head of the chain. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Callers are responsible for ensuring the size of the memory is correct. /// - public ManagedChain Truncate(out T12 item12) + internal ManagedChain(nint headPtr) { - item12 = Item12; - - var newSize = MemorySize - Item12Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); - ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = null; - return new ManagedChain(newHeadPtr); + _headPtr = headPtr; } /// - /// Creates a new with 14 items, by appending to - /// the end of this chain. + /// Creates a new with 12 items. /// - /// Item 13. - /// Type of Item 13 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T13 item13 = default) - where T13: struct, IExtendsChain + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - return new ManagedChain(this, item13); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; + item6.StructureType(); + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; + item7.StructureType(); + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; + item8.StructureType(); + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; + item9.StructureType(); + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; + item10.StructureType(); + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; + item11.StructureType(); + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + Item11Ptr->PNext = null; } /// @@ -9048,11 +15449,10 @@ public override IEnumerator GetEnumerator() yield return Item9; yield return Item10; yield return Item11; - yield return Item12; } /// - public override int Count => 13; + public override int Count => 12; /// public override IChainable this[int index] @@ -9070,10 +15470,170 @@ public override IChainable this[int index] 9 => Item9, 10 => Item10, 11 => Item11, - 12 => Item12, _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(", "); + sb.Append((object) Item8); + sb.Append(", "); + sb.Append((object) Item9); + sb.Append(", "); + sb.Append((object) Item10); + sb.Append(", "); + sb.Append((object) Item11); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// @@ -9089,8 +15649,7 @@ public override IChainable this[int index] /// Item 9. /// Item 10. /// Item 11. - /// Item 12. - public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10, out T11 item11, out T12 item12) + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10, out T11 item11) { head = Head; item1 = Item1; @@ -9104,7 +15663,6 @@ public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item item9 = Item9; item10 = Item10; item11 = Item11; - item12 = Item12; } /// @@ -9128,7 +15686,6 @@ public override void Dispose() Marshal.DestroyStructure(headPtr + Item9Offset); Marshal.DestroyStructure(headPtr + Item10Offset); Marshal.DestroyStructure(headPtr + Item11Offset); - Marshal.DestroyStructure(headPtr + Item12Offset); // Free memory block Marshal.FreeHGlobal(headPtr); @@ -9136,7 +15693,7 @@ public override void Dispose() } /// -/// A safely manages the pointers of a managed structure chain. +/// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. @@ -9151,23 +15708,26 @@ public override void Dispose() /// Type of Item 10. /// Type of Item 11. /// Type of Item 12. -/// Type of Item 13. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -9211,905 +15771,1288 @@ public unsafe class ManagedChain /// Gets the size (in bytes) of the Item 1. /// - public static readonly int Item4Size = Marshal.SizeOf(); + public static readonly int Item4Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item5Offset = Item4Offset + Item4Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item5Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item6Offset = Item5Offset + Item5Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item6Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item7Offset = Item6Offset + Item6Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item7Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item8Offset = Item7Offset + Item7Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item8Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item9Offset = Item8Offset + Item8Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item9Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item10Offset = Item9Offset + Item9Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item10Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item11Offset = Item10Offset + Item10Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item11Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item12Offset = Item11Offset + Item11Size; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item12Size = Marshal.SizeOf(); + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item12Offset + Item12Size; + + /// + public override int Size => MemorySize; + + private nint _headPtr; + + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((BaseInStructure*) _headPtr); + set + { + value.StructureType(); + var ptr = (BaseInStructure*) _headPtr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); + + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef(Item1Ptr); + set + { + value.StructureType(); + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); + + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef(Item2Ptr); + set + { + value.StructureType(); + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } + + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); + + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef(Item3Ptr); + set + { + value.StructureType(); + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the offset to the start of . + /// Gets a pointer to the second item in the chain. /// - public static readonly int Item5Offset = Item4Offset + Item4Size; + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets or sets item #4 in the chain. /// - public static readonly int Item5Size = Marshal.SizeOf(); + public T4 Item4 + { + get => Unsafe.AsRef(Item4Ptr); + set + { + value.StructureType(); + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the offset to the start of . + /// Gets a pointer to the second item in the chain. /// - public static readonly int Item6Offset = Item5Offset + Item5Size; + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets or sets item #5 in the chain. /// - public static readonly int Item6Size = Marshal.SizeOf(); + public T5 Item5 + { + get => Unsafe.AsRef(Item5Ptr); + set + { + value.StructureType(); + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the offset to the start of . + /// Gets a pointer to the second item in the chain. /// - public static readonly int Item7Offset = Item6Offset + Item6Size; + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets or sets item #6 in the chain. /// - public static readonly int Item7Size = Marshal.SizeOf(); + public T6 Item6 + { + get => Unsafe.AsRef(Item6Ptr); + set + { + value.StructureType(); + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the offset to the start of . + /// Gets a pointer to the second item in the chain. /// - public static readonly int Item8Offset = Item7Offset + Item7Size; + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets or sets item #7 in the chain. /// - public static readonly int Item8Size = Marshal.SizeOf(); + public T7 Item7 + { + get => Unsafe.AsRef(Item7Ptr); + set + { + value.StructureType(); + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the offset to the start of . + /// Gets a pointer to the second item in the chain. /// - public static readonly int Item9Offset = Item8Offset + Item8Size; + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets or sets item #8 in the chain. /// - public static readonly int Item9Size = Marshal.SizeOf(); + public T8 Item8 + { + get => Unsafe.AsRef(Item8Ptr); + set + { + value.StructureType(); + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the offset to the start of . + /// Gets a pointer to the second item in the chain. /// - public static readonly int Item10Offset = Item9Offset + Item9Size; + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets or sets item #9 in the chain. /// - public static readonly int Item10Size = Marshal.SizeOf(); + public T9 Item9 + { + get => Unsafe.AsRef(Item9Ptr); + set + { + value.StructureType(); + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the offset to the start of . + /// Gets a pointer to the second item in the chain. /// - public static readonly int Item11Offset = Item10Offset + Item10Size; + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets or sets item #10 in the chain. /// - public static readonly int Item11Size = Marshal.SizeOf(); + public T10 Item10 + { + get => Unsafe.AsRef(Item10Ptr); + set + { + value.StructureType(); + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the offset to the start of . + /// Gets a pointer to the second item in the chain. /// - public static readonly int Item12Offset = Item11Offset + Item11Size; + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets or sets item #11 in the chain. /// - public static readonly int Item12Size = Marshal.SizeOf(); + public T11 Item11 + { + get => Unsafe.AsRef(Item11Ptr); + set + { + value.StructureType(); + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the offset to the start of . + /// Gets a pointer to the second item in the chain. /// - public static readonly int Item13Offset = Item12Offset + Item12Size; + public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets or sets item #12 in the chain. /// - public static readonly int Item13Size = Marshal.SizeOf(); + public T12 Item12 + { + get => Unsafe.AsRef(Item12Ptr); + set + { + value.StructureType(); + var ptr = Item12Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// Creates a new with 13 items from an existing memory block. /// - public static readonly int MemorySize = Item13Offset + Item13Size; - - private nint _headPtr; + /// The pointer to the head of the chain. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } /// - /// Gets a pointer to the current head. + /// Creates a new with 13 items. /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default) + : this(Marshal.AllocHGlobal(MemorySize)) + { + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; + item6.StructureType(); + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; + item7.StructureType(); + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; + item8.StructureType(); + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; + item9.StructureType(); + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; + item10.StructureType(); + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; + item11.StructureType(); + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + itemPtr = Item12Ptr; + item12.StructureType(); + Marshal.StructureToPtr(item12, (nint)itemPtr, false); + Item11Ptr->PNext = itemPtr; + Item12Ptr->PNext = null; + } - /// - /// Gets or sets the head of the chain. - /// - public TChain Head + /// + public override IEnumerator GetEnumerator() { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; - } + yield return Head; + yield return Item1; + yield return Item2; + yield return Item3; + yield return Item4; + yield return Item5; + yield return Item6; + yield return Item7; + yield return Item8; + yield return Item9; + yield return Item10; + yield return Item11; + yield return Item12; } - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); + /// + public override int Count => 13; - /// - /// Gets or sets item #1 in the chain. - /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set + /// + public override IChainable this[int index] + => index switch { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + 0 => Head, + 1 => Item1, + 2 => Item2, + 3 => Item3, + 4 => Item4, + 5 => Item5, + 6 => Item6, + 7 => Item7, + 8 => Item8, + 9 => Item9, + 10 => Item10, + 11 => Item11, + 12 => Item12, + _ => throw new IndexOutOfRangeException() + }; /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item12Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(", "); + sb.Append((object) Item8); + sb.Append(", "); + sb.Append((object) Item9); + sb.Append(", "); + sb.Append((object) Item10); + sb.Append(", "); + sb.Append((object) Item11); + sb.Append(", "); + sb.Append((object) Item12); + sb.Append(")"); + return sb.ToString(); } /// - /// Gets a pointer to the second item in the chain. + /// Deconstructs this chain. /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + public void Deconstruct(out TChain head, out T1 item1, out T2 item2, out T3 item3, out T4 item4, out T5 item5, out T6 item6, out T7 item7, out T8 item8, out T9 item9, out T10 item10, out T11 item11, out T12 item12) + { + head = Head; + item1 = Item1; + item2 = Item2; + item3 = Item3; + item4 = Item4; + item5 = Item5; + item6 = Item6; + item7 = Item7; + item8 = Item8; + item9 = Item9; + item10 = Item10; + item11 = Item11; + item12 = Item12; + } - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 + /// + public override void Dispose() { - get => Unsafe.AsRef(Item4Ptr); - set - { - value.StructureType(); - var ptr = Item4Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; } + + // Destroy all structures + Marshal.DestroyStructure(headPtr); + Marshal.DestroyStructure(headPtr + Item1Offset); + Marshal.DestroyStructure(headPtr + Item2Offset); + Marshal.DestroyStructure(headPtr + Item3Offset); + Marshal.DestroyStructure(headPtr + Item4Offset); + Marshal.DestroyStructure(headPtr + Item5Offset); + Marshal.DestroyStructure(headPtr + Item6Offset); + Marshal.DestroyStructure(headPtr + Item7Offset); + Marshal.DestroyStructure(headPtr + Item8Offset); + Marshal.DestroyStructure(headPtr + Item9Offset); + Marshal.DestroyStructure(headPtr + Item10Offset); + Marshal.DestroyStructure(headPtr + Item11Offset); + Marshal.DestroyStructure(headPtr + Item12Offset); + + // Free memory block + Marshal.FreeHGlobal(headPtr); } +} +/// +/// A safely manages the pointers of a managed structure chain. +/// +/// The chain type +/// Type of Item 1. +/// Type of Item 2. +/// Type of Item 3. +/// Type of Item 4. +/// Type of Item 5. +/// Type of Item 6. +/// Type of Item 7. +/// Type of Item 8. +/// Type of Item 9. +/// Type of Item 10. +/// Type of Item 11. +/// Type of Item 12. +/// Type of Item 13. +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable +{ /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the default structure header. /// - public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); + public static readonly int HeaderSize = Marshal.SizeOf(); /// - /// Gets or sets item #5 in the chain. + /// Gets the size (in bytes) of the head structure. /// - public T5 Item5 - { - get => Unsafe.AsRef(Item5Ptr); - set - { - value.StructureType(); - var ptr = Item5Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int HeadSize = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); + public static readonly int Item1Offset = HeadSize; /// - /// Gets or sets item #6 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T6 Item6 - { - get => Unsafe.AsRef(Item6Ptr); - set - { - value.StructureType(); - var ptr = Item6Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item1Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); + public static readonly int Item2Offset = Item1Offset + Item1Size; /// - /// Gets or sets item #7 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T7 Item7 - { - get => Unsafe.AsRef(Item7Ptr); - set - { - value.StructureType(); - var ptr = Item7Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item2Size = Marshal.SizeOf(); + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item3Offset = Item2Offset + Item2Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); + public static readonly int Item3Size = Marshal.SizeOf(); /// - /// Gets or sets item #8 in the chain. + /// Gets the offset to the start of . /// - public T8 Item8 - { - get => Unsafe.AsRef(Item8Ptr); - set - { - value.StructureType(); - var ptr = Item8Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item4Offset = Item3Offset + Item3Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); + public static readonly int Item4Size = Marshal.SizeOf(); /// - /// Gets or sets item #9 in the chain. + /// Gets the offset to the start of . /// - public T9 Item9 - { - get => Unsafe.AsRef(Item9Ptr); - set - { - value.StructureType(); - var ptr = Item9Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item5Offset = Item4Offset + Item4Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); + public static readonly int Item5Size = Marshal.SizeOf(); /// - /// Gets or sets item #10 in the chain. + /// Gets the offset to the start of . /// - public T10 Item10 - { - get => Unsafe.AsRef(Item10Ptr); - set - { - value.StructureType(); - var ptr = Item10Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item6Offset = Item5Offset + Item5Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); + public static readonly int Item6Size = Marshal.SizeOf(); /// - /// Gets or sets item #11 in the chain. + /// Gets the offset to the start of . /// - public T11 Item11 - { - get => Unsafe.AsRef(Item11Ptr); - set - { - value.StructureType(); - var ptr = Item11Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item7Offset = Item6Offset + Item6Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); + public static readonly int Item7Size = Marshal.SizeOf(); /// - /// Gets or sets item #12 in the chain. + /// Gets the offset to the start of . /// - public T12 Item12 - { - get => Unsafe.AsRef(Item12Ptr); - set - { - value.StructureType(); - var ptr = Item12Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item8Offset = Item7Offset + Item7Size; /// - /// Gets a pointer to the second item in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public BaseInStructure* Item13Ptr => (BaseInStructure*) (_headPtr + Item13Offset); + public static readonly int Item8Size = Marshal.SizeOf(); /// - /// Gets or sets item #13 in the chain. + /// Gets the offset to the start of . /// - public T13 Item13 - { - get => Unsafe.AsRef(Item13Ptr); - set - { - value.StructureType(); - var ptr = Item13Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item9Offset = Item8Offset + Item8Size; /// - /// Creates a new with 14 items from an existing memory block. + /// Gets the size (in bytes) of the Item 1. /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } + public static readonly int Item9Size = Marshal.SizeOf(); /// - /// Creates a new with 14 items. + /// Gets the offset to the start of . /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - itemPtr = Item6Ptr; - item6.StructureType(); - Marshal.StructureToPtr(item6, (nint)itemPtr, false); - Item5Ptr->PNext = itemPtr; - itemPtr = Item7Ptr; - item7.StructureType(); - Marshal.StructureToPtr(item7, (nint)itemPtr, false); - Item6Ptr->PNext = itemPtr; - itemPtr = Item8Ptr; - item8.StructureType(); - Marshal.StructureToPtr(item8, (nint)itemPtr, false); - Item7Ptr->PNext = itemPtr; - itemPtr = Item9Ptr; - item9.StructureType(); - Marshal.StructureToPtr(item9, (nint)itemPtr, false); - Item8Ptr->PNext = itemPtr; - itemPtr = Item10Ptr; - item10.StructureType(); - Marshal.StructureToPtr(item10, (nint)itemPtr, false); - Item9Ptr->PNext = itemPtr; - itemPtr = Item11Ptr; - item11.StructureType(); - Marshal.StructureToPtr(item11, (nint)itemPtr, false); - Item10Ptr->PNext = itemPtr; - itemPtr = Item12Ptr; - item12.StructureType(); - Marshal.StructureToPtr(item12, (nint)itemPtr, false); - Item11Ptr->PNext = itemPtr; - itemPtr = Item13Ptr; - item13.StructureType(); - Marshal.StructureToPtr(item13, (nint)itemPtr, false); - Item12Ptr->PNext = itemPtr; - Item13Ptr->PNext = null; - } + public static readonly int Item10Offset = Item9Offset + Item9Size; /// - /// Creates a new with 14 items from an existing unmanaged chain. + /// Gets the size (in bytes) of the Item 1. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; + public static readonly int Item10Size = Marshal.SizeOf(); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets the offset to the start of . + /// + public static readonly int Item11Offset = Item10Offset + Item10Size; - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item11Size = Marshal.SizeOf(); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets the offset to the start of . + /// + public static readonly int Item12Offset = Item11Offset + Item11Size; - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item12Size = Marshal.SizeOf(); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets the offset to the start of . + /// + public static readonly int Item13Offset = Item12Offset + Item12Size; - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item13Size = Marshal.SizeOf(); - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = Item13Offset + Item13Size; + + /// + public override int Size => MemorySize; - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } + private nint _headPtr; + + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((BaseInStructure*) _headPtr); + set + { + value.StructureType(); + var ptr = (BaseInStructure*) _headPtr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item4, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #1 in the chain. + /// + public T1 Item1 + { + get => Unsafe.AsRef(Item1Ptr); + set + { + value.StructureType(); + var ptr = Item1Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item5, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item6 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #2 in the chain. + /// + public T2 Item2 + { + get => Unsafe.AsRef(Item2Ptr); + set + { + value.StructureType(); + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item6, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - T7 item7 = default; - expectedStructureType = item7.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item7 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef(Item3Ptr); + set + { + value.StructureType(); + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item7, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - T8 item8 = default; - expectedStructureType = item8.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item8 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef(Item4Ptr); + set + { + value.StructureType(); + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item8, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - T9 item9 = default; - expectedStructureType = item9.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item9 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef(Item5Ptr); + set + { + value.StructureType(); + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item9, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); - T10 item10 = default; - expectedStructureType = item10.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item10 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef(Item6Ptr); + set + { + value.StructureType(); + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item10, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); - T11 item11 = default; - expectedStructureType = item11.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item11 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef(Item7Ptr); + set + { + value.StructureType(); + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item11, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item12Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); - T12 item12 = default; - expectedStructureType = item12.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 13; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item12 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef(Item8Ptr); + set + { + value.StructureType(); + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item12, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item13Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); - T13 item13 = default; - expectedStructureType = item13.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 14"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 14; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 14"); - existingPtr->PNext = null; - } - item13 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef(Item9Ptr); + set + { + value.StructureType(); + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item13, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); } /// - /// Creates a new with 14 by copying this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); + + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); - ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); - ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); - return new ManagedChain(newHeadPtr); + get => Unsafe.AsRef(Item10Ptr); + set + { + value.StructureType(); + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 14 items, by appending - /// to the end of this chain. + /// Gets a pointer to the second item in the chain. /// - /// The chain to append to. - /// Item 13. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T13 item13 = default) - : this(Marshal.AllocHGlobal(MemorySize)) + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); + + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 { - var previousSize = MemorySize - Item13Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 13 - item13.StructureType(); - Marshal.StructureToPtr(item13, _headPtr + previousSize, false); + get => Unsafe.AsRef(Item11Ptr); + set + { + value.StructureType(); + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); - ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); - ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); - ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); - ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); - ((BaseInStructure*)(_headPtr + Item11Offset))->PNext = (BaseInStructure*) (_headPtr + Item12Offset); - ((BaseInStructure*)(_headPtr + Item12Offset))->PNext = (BaseInStructure*) (_headPtr + Item13Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); + + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef(Item12Ptr); + set + { + value.StructureType(); + var ptr = Item12Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 13 items, by removing the last item - /// from this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() + public BaseInStructure* Item13Ptr => (BaseInStructure*) (_headPtr + Item13Offset); + + /// + /// Gets or sets item #13 in the chain. + /// + public T13 Item13 { - return Truncate(out var _); + get => Unsafe.AsRef(Item13Ptr); + set + { + value.StructureType(); + var ptr = Item13Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 13 items, by removing - /// from the end of this chain. + /// Creates a new with 14 items from an existing memory block. /// + /// The pointer to the head of the chain. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Callers are responsible for ensuring the size of the memory is correct. /// - public ManagedChain Truncate(out T13 item13) + internal ManagedChain(nint headPtr) { - item13 = Item13; - - var newSize = MemorySize - Item13Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); - ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); - ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = null; - return new ManagedChain(newHeadPtr); + _headPtr = headPtr; } /// - /// Creates a new with 15 items, by appending to - /// the end of this chain. + /// Creates a new with 14 items. /// - /// Item 14. - /// Type of Item 14 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T14 item14 = default) - where T14: struct, IExtendsChain + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - return new ManagedChain(this, item14); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; + item6.StructureType(); + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; + item7.StructureType(); + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; + item8.StructureType(); + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; + item9.StructureType(); + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; + item10.StructureType(); + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; + item11.StructureType(); + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + itemPtr = Item12Ptr; + item12.StructureType(); + Marshal.StructureToPtr(item12, (nint)itemPtr, false); + Item11Ptr->PNext = itemPtr; + itemPtr = Item13Ptr; + item13.StructureType(); + Marshal.StructureToPtr(item13, (nint)itemPtr, false); + Item12Ptr->PNext = itemPtr; + Item13Ptr->PNext = null; } /// @@ -10155,6 +17098,187 @@ public override IChainable this[int index] _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item12Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item13Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(", "); + sb.Append((object) Item8); + sb.Append(", "); + sb.Append((object) Item9); + sb.Append(", "); + sb.Append((object) Item10); + sb.Append(", "); + sb.Append((object) Item11); + sb.Append(", "); + sb.Append((object) Item12); + sb.Append(", "); + sb.Append((object) Item13); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// @@ -10237,23 +17361,28 @@ public override void Dispose() /// Type of Item 12. /// Type of Item 13. /// Type of Item 14. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -10403,13 +17532,14 @@ public unsafe class ManagedChain public static readonly int MemorySize = Item14Offset + Item14Size; - + + /// + public override int Size => MemorySize; + private nint _headPtr; - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. @@ -10451,228 +17581,18 @@ public T1 Item1 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); - - /// - /// Gets or sets item #2 in the chain. - /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - - /// - /// Gets or sets item #3 in the chain. - /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - - /// - /// Gets or sets item #4 in the chain. - /// - public T4 Item4 - { - get => Unsafe.AsRef(Item4Ptr); - set - { - value.StructureType(); - var ptr = Item4Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - - /// - /// Gets or sets item #5 in the chain. - /// - public T5 Item5 - { - get => Unsafe.AsRef(Item5Ptr); - set - { - value.StructureType(); - var ptr = Item5Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); - - /// - /// Gets or sets item #6 in the chain. - /// - public T6 Item6 - { - get => Unsafe.AsRef(Item6Ptr); - set - { - value.StructureType(); - var ptr = Item6Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); - - /// - /// Gets or sets item #7 in the chain. - /// - public T7 Item7 - { - get => Unsafe.AsRef(Item7Ptr); - set - { - value.StructureType(); - var ptr = Item7Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); - - /// - /// Gets or sets item #8 in the chain. - /// - public T8 Item8 - { - get => Unsafe.AsRef(Item8Ptr); - set - { - value.StructureType(); - var ptr = Item8Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); - - /// - /// Gets or sets item #9 in the chain. - /// - public T9 Item9 - { - get => Unsafe.AsRef(Item9Ptr); - set - { - value.StructureType(); - var ptr = Item9Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); - - /// - /// Gets or sets item #10 in the chain. - /// - public T10 Item10 - { - get => Unsafe.AsRef(Item10Ptr); - set - { - value.StructureType(); - var ptr = Item10Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); - - /// - /// Gets or sets item #11 in the chain. - /// - public T11 Item11 - { - get => Unsafe.AsRef(Item11Ptr); - set - { - value.StructureType(); - var ptr = Item11Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// - /// Gets or sets item #12 in the chain. + /// Gets or sets item #2 in the chain. /// - public T12 Item12 + public T2 Item2 { - get => Unsafe.AsRef(Item12Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var ptr = Item12Ptr; + var ptr = Item2Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -10682,18 +17602,18 @@ public T12 Item12 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item13Ptr => (BaseInStructure*) (_headPtr + Item13Offset); + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); /// - /// Gets or sets item #13 in the chain. + /// Gets or sets item #3 in the chain. /// - public T13 Item13 + public T3 Item3 { - get => Unsafe.AsRef(Item13Ptr); + get => Unsafe.AsRef(Item3Ptr); set { value.StructureType(); - var ptr = Item13Ptr; + var ptr = Item3Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -10703,18 +17623,18 @@ public T13 Item13 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item14Ptr => (BaseInStructure*) (_headPtr + Item14Offset); + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); /// - /// Gets or sets item #14 in the chain. + /// Gets or sets item #4 in the chain. /// - public T14 Item14 + public T4 Item4 { - get => Unsafe.AsRef(Item14Ptr); + get => Unsafe.AsRef(Item4Ptr); set { value.StructureType(); - var ptr = Item14Ptr; + var ptr = Item4Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -10722,540 +17642,307 @@ public T14 Item14 } /// - /// Creates a new with 15 items from an existing memory block. - /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } - - /// - /// Creates a new with 15 items. + /// Gets a pointer to the second item in the chain. /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - /// Item 14. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - itemPtr = Item6Ptr; - item6.StructureType(); - Marshal.StructureToPtr(item6, (nint)itemPtr, false); - Item5Ptr->PNext = itemPtr; - itemPtr = Item7Ptr; - item7.StructureType(); - Marshal.StructureToPtr(item7, (nint)itemPtr, false); - Item6Ptr->PNext = itemPtr; - itemPtr = Item8Ptr; - item8.StructureType(); - Marshal.StructureToPtr(item8, (nint)itemPtr, false); - Item7Ptr->PNext = itemPtr; - itemPtr = Item9Ptr; - item9.StructureType(); - Marshal.StructureToPtr(item9, (nint)itemPtr, false); - Item8Ptr->PNext = itemPtr; - itemPtr = Item10Ptr; - item10.StructureType(); - Marshal.StructureToPtr(item10, (nint)itemPtr, false); - Item9Ptr->PNext = itemPtr; - itemPtr = Item11Ptr; - item11.StructureType(); - Marshal.StructureToPtr(item11, (nint)itemPtr, false); - Item10Ptr->PNext = itemPtr; - itemPtr = Item12Ptr; - item12.StructureType(); - Marshal.StructureToPtr(item12, (nint)itemPtr, false); - Item11Ptr->PNext = itemPtr; - itemPtr = Item13Ptr; - item13.StructureType(); - Marshal.StructureToPtr(item13, (nint)itemPtr, false); - Item12Ptr->PNext = itemPtr; - itemPtr = Item14Ptr; - item14.StructureType(); - Marshal.StructureToPtr(item14, (nint)itemPtr, false); - Item13Ptr->PNext = itemPtr; - Item14Ptr->PNext = null; - } + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); /// - /// Creates a new with 15 items from an existing unmanaged chain. + /// Gets or sets item #5 in the chain. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) + public T5 Item5 { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item5, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item6 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item6, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T7 item7 = default; - expectedStructureType = item7.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item7 = Unsafe.AsRef(existingPtr); - } + get => Unsafe.AsRef(Item5Ptr); + set + { + value.StructureType(); + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item7, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); - T8 item8 = default; - expectedStructureType = item8.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item8 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef(Item6Ptr); + set + { + value.StructureType(); + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item8, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); - T9 item9 = default; - expectedStructureType = item9.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item9 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef(Item7Ptr); + set + { + value.StructureType(); + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item9, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); - T10 item10 = default; - expectedStructureType = item10.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item10 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef(Item8Ptr); + set + { + value.StructureType(); + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item10, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); - T11 item11 = default; - expectedStructureType = item11.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item11 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef(Item9Ptr); + set + { + value.StructureType(); + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item11, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item12Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); - T12 item12 = default; - expectedStructureType = item12.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 13; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item12 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef(Item10Ptr); + set + { + value.StructureType(); + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item12, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item13Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); - T13 item13 = default; - expectedStructureType = item13.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 14; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item13 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef(Item11Ptr); + set + { + value.StructureType(); + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item13, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item14Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); - T14 item14 = default; - expectedStructureType = item14.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 15"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 15; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 15"); - existingPtr->PNext = null; - } - item14 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef(Item12Ptr); + set + { + value.StructureType(); + var ptr = Item12Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item14, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); } /// - /// Creates a new with 15 by copying this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() + public BaseInStructure* Item13Ptr => (BaseInStructure*) (_headPtr + Item13Offset); + + /// + /// Gets or sets item #13 in the chain. + /// + public T13 Item13 { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); - ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); - ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); - ((BaseInStructure*)(newHeadPtr + Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item14Offset); - return new ManagedChain(newHeadPtr); + get => Unsafe.AsRef(Item13Ptr); + set + { + value.StructureType(); + var ptr = Item13Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 15 items, by appending - /// to the end of this chain. + /// Gets a pointer to the second item in the chain. /// - /// The chain to append to. - /// Item 14. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T14 item14 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item14Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 14 - item14.StructureType(); - Marshal.StructureToPtr(item14, _headPtr + previousSize, false); - - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); - ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); - ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); - ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); - ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); - ((BaseInStructure*)(_headPtr + Item11Offset))->PNext = (BaseInStructure*) (_headPtr + Item12Offset); - ((BaseInStructure*)(_headPtr + Item12Offset))->PNext = (BaseInStructure*) (_headPtr + Item13Offset); - ((BaseInStructure*)(_headPtr + Item13Offset))->PNext = (BaseInStructure*) (_headPtr + Item14Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; - } + public BaseInStructure* Item14Ptr => (BaseInStructure*) (_headPtr + Item14Offset); /// - /// Creates a new with 14 items, by removing the last item - /// from this chain. + /// Gets or sets item #14 in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() + public T14 Item14 { - return Truncate(out var _); + get => Unsafe.AsRef(Item14Ptr); + set + { + value.StructureType(); + var ptr = Item14Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 14 items, by removing - /// from the end of this chain. + /// Creates a new with 15 items from an existing memory block. /// + /// The pointer to the head of the chain. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Callers are responsible for ensuring the size of the memory is correct. /// - public ManagedChain Truncate(out T14 item14) + internal ManagedChain(nint headPtr) { - item14 = Item14; - - var newSize = MemorySize - Item14Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); - ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); - ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); - ((BaseInStructure*)(newHeadPtr + Item13Offset))->PNext = null; - return new ManagedChain(newHeadPtr); + _headPtr = headPtr; } /// - /// Creates a new with 16 items, by appending to - /// the end of this chain. + /// Creates a new with 15 items. /// - /// Item 15. - /// Type of Item 15 - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Append(T15 item15 = default) - where T15: struct, IExtendsChain + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default) + : this(Marshal.AllocHGlobal(MemorySize)) { - return new ManagedChain(this, item15); + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; + item6.StructureType(); + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; + item7.StructureType(); + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; + item8.StructureType(); + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; + item9.StructureType(); + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; + item10.StructureType(); + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; + item11.StructureType(); + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + itemPtr = Item12Ptr; + item12.StructureType(); + Marshal.StructureToPtr(item12, (nint)itemPtr, false); + Item11Ptr->PNext = itemPtr; + itemPtr = Item13Ptr; + item13.StructureType(); + Marshal.StructureToPtr(item13, (nint)itemPtr, false); + Item12Ptr->PNext = itemPtr; + itemPtr = Item14Ptr; + item14.StructureType(); + Marshal.StructureToPtr(item14, (nint)itemPtr, false); + Item13Ptr->PNext = itemPtr; + Item14Ptr->PNext = null; } /// @@ -11303,6 +17990,197 @@ public override IChainable this[int index] _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item12Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item13Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item14Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(", "); + sb.Append((object) Item8); + sb.Append(", "); + sb.Append((object) Item9); + sb.Append(", "); + sb.Append((object) Item10); + sb.Append(", "); + sb.Append((object) Item11); + sb.Append(", "); + sb.Append((object) Item12); + sb.Append(", "); + sb.Append((object) Item13); + sb.Append(", "); + sb.Append((object) Item14); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// @@ -11387,478 +18265,211 @@ public override void Dispose() /// Type of Item 11. /// Type of Item 12. /// Type of Item 13. -/// Type of Item 14. -/// Type of Item 15. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain - where T2 : struct, IExtendsChain - where T3 : struct, IExtendsChain - where T4 : struct, IExtendsChain - where T5 : struct, IExtendsChain - where T6 : struct, IExtendsChain - where T7 : struct, IExtendsChain - where T8 : struct, IExtendsChain - where T9 : struct, IExtendsChain - where T10 : struct, IExtendsChain - where T11 : struct, IExtendsChain - where T12 : struct, IExtendsChain - where T13 : struct, IExtendsChain - where T14 : struct, IExtendsChain - where T15 : struct, IExtendsChain -{ - /// - /// Gets the size (in bytes) of the head structure. - /// - public static readonly int HeadSize = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item1Offset = HeadSize; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item1Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item2Offset = Item1Offset + Item1Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item2Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item3Offset = Item2Offset + Item2Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item3Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item4Offset = Item3Offset + Item3Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item4Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item5Offset = Item4Offset + Item4Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item5Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item6Offset = Item5Offset + Item5Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item6Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item7Offset = Item6Offset + Item6Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item7Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item8Offset = Item7Offset + Item7Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item8Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item9Offset = Item8Offset + Item8Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item9Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item10Offset = Item9Offset + Item9Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item10Size = Marshal.SizeOf(); - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item11Offset = Item10Offset + Item10Size; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item11Size = Marshal.SizeOf(); - +/// Type of Item 14. +/// Type of Item 15. +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable + where T2 : struct, IChainable + where T3 : struct, IChainable + where T4 : struct, IChainable + where T5 : struct, IChainable + where T6 : struct, IChainable + where T7 : struct, IChainable + where T8 : struct, IChainable + where T9 : struct, IChainable + where T10 : struct, IChainable + where T11 : struct, IChainable + where T12 : struct, IChainable + where T13 : struct, IChainable + where T14 : struct, IChainable + where T15 : struct, IChainable +{ /// - /// Gets the offset to the start of . + /// Gets the size (in bytes) of the default structure header. /// - public static readonly int Item12Offset = Item11Offset + Item11Size; + public static readonly int HeaderSize = Marshal.SizeOf(); /// - /// Gets the size (in bytes) of the Item 1. + /// Gets the size (in bytes) of the head structure. /// - public static readonly int Item12Size = Marshal.SizeOf(); + public static readonly int HeadSize = Marshal.SizeOf(); /// /// Gets the offset to the start of . /// - public static readonly int Item13Offset = Item12Offset + Item12Size; + public static readonly int Item1Offset = HeadSize; /// /// Gets the size (in bytes) of the Item 1. /// - public static readonly int Item13Size = Marshal.SizeOf(); + public static readonly int Item1Size = Marshal.SizeOf(); /// /// Gets the offset to the start of . /// - public static readonly int Item14Offset = Item13Offset + Item13Size; + public static readonly int Item2Offset = Item1Offset + Item1Size; /// /// Gets the size (in bytes) of the Item 1. /// - public static readonly int Item14Size = Marshal.SizeOf(); + public static readonly int Item2Size = Marshal.SizeOf(); /// /// Gets the offset to the start of . /// - public static readonly int Item15Offset = Item14Offset + Item14Size; + public static readonly int Item3Offset = Item2Offset + Item2Size; /// /// Gets the size (in bytes) of the Item 1. /// - public static readonly int Item15Size = Marshal.SizeOf(); - - /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. - /// - public static readonly int MemorySize = Item15Offset + Item15Size; - - private nint _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item3Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); + public static readonly int Item4Offset = Item3Offset + Item3Size; /// - /// Gets or sets item #1 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T1 Item1 - { - get => Unsafe.AsRef(Item1Ptr); - set - { - value.StructureType(); - var ptr = Item1Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item4Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); + public static readonly int Item5Offset = Item4Offset + Item4Size; /// - /// Gets or sets item #2 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T2 Item2 - { - get => Unsafe.AsRef(Item2Ptr); - set - { - value.StructureType(); - var ptr = Item2Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item5Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); + public static readonly int Item6Offset = Item5Offset + Item5Size; /// - /// Gets or sets item #3 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T3 Item3 - { - get => Unsafe.AsRef(Item3Ptr); - set - { - value.StructureType(); - var ptr = Item3Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item6Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); + public static readonly int Item7Offset = Item6Offset + Item6Size; /// - /// Gets or sets item #4 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T4 Item4 - { - get => Unsafe.AsRef(Item4Ptr); - set - { - value.StructureType(); - var ptr = Item4Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item7Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); + public static readonly int Item8Offset = Item7Offset + Item7Size; /// - /// Gets or sets item #5 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T5 Item5 - { - get => Unsafe.AsRef(Item5Ptr); - set - { - value.StructureType(); - var ptr = Item5Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item8Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); + public static readonly int Item9Offset = Item8Offset + Item8Size; /// - /// Gets or sets item #6 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T6 Item6 - { - get => Unsafe.AsRef(Item6Ptr); - set - { - value.StructureType(); - var ptr = Item6Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item9Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); + public static readonly int Item10Offset = Item9Offset + Item9Size; /// - /// Gets or sets item #7 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T7 Item7 - { - get => Unsafe.AsRef(Item7Ptr); - set - { - value.StructureType(); - var ptr = Item7Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item10Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); + public static readonly int Item11Offset = Item10Offset + Item10Size; /// - /// Gets or sets item #8 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T8 Item8 - { - get => Unsafe.AsRef(Item8Ptr); - set - { - value.StructureType(); - var ptr = Item8Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item11Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); + public static readonly int Item12Offset = Item11Offset + Item11Size; /// - /// Gets or sets item #9 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T9 Item9 - { - get => Unsafe.AsRef(Item9Ptr); - set - { - value.StructureType(); - var ptr = Item9Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item12Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); + public static readonly int Item13Offset = Item12Offset + Item12Size; /// - /// Gets or sets item #10 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T10 Item10 - { - get => Unsafe.AsRef(Item10Ptr); - set - { - value.StructureType(); - var ptr = Item10Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item13Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); + public static readonly int Item14Offset = Item13Offset + Item13Size; /// - /// Gets or sets item #11 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T11 Item11 - { - get => Unsafe.AsRef(Item11Ptr); - set - { - value.StructureType(); - var ptr = Item11Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item14Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the offset to the start of . /// - public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); + public static readonly int Item15Offset = Item14Offset + Item14Size; /// - /// Gets or sets item #12 in the chain. + /// Gets the size (in bytes) of the Item 1. /// - public T12 Item12 - { - get => Unsafe.AsRef(Item12Ptr); - set - { - value.StructureType(); - var ptr = Item12Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } + public static readonly int Item15Size = Marshal.SizeOf(); /// - /// Gets a pointer to the second item in the chain. + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// - public BaseInStructure* Item13Ptr => (BaseInStructure*) (_headPtr + Item13Offset); + public static readonly int MemorySize = Item15Offset + Item15Size; + + /// + public override int Size => MemorySize; + + private nint _headPtr; + + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// - /// Gets or sets item #13 in the chain. + /// Gets or sets the head of the chain. /// - public T13 Item13 + public TChain Head { - get => Unsafe.AsRef(Item13Ptr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = Item13Ptr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); + Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; } } @@ -11866,18 +18477,18 @@ public T13 Item13 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item14Ptr => (BaseInStructure*) (_headPtr + Item14Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// - /// Gets or sets item #14 in the chain. + /// Gets or sets item #1 in the chain. /// - public T14 Item14 + public T1 Item1 { - get => Unsafe.AsRef(Item14Ptr); + get => Unsafe.AsRef(Item1Ptr); set { value.StructureType(); - var ptr = Item14Ptr; + var ptr = Item1Ptr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, (nint)ptr, true); ptr->PNext = nextPtr; @@ -11887,573 +18498,394 @@ public T14 Item14 /// /// Gets a pointer to the second item in the chain. /// - public BaseInStructure* Item15Ptr => (BaseInStructure*) (_headPtr + Item15Offset); + public BaseInStructure* Item2Ptr => (BaseInStructure*) (_headPtr + Item2Offset); /// - /// Gets or sets item #15 in the chain. + /// Gets or sets item #2 in the chain. /// - public T15 Item15 + public T2 Item2 { - get => Unsafe.AsRef(Item15Ptr); + get => Unsafe.AsRef(Item2Ptr); set { value.StructureType(); - var ptr = Item15Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } - - /// - /// Creates a new with 16 items from an existing memory block. - /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } - - /// - /// Creates a new with 16 items. - /// - /// The head of the chain. - /// Item 1. - /// Item 2. - /// Item 3. - /// Item 4. - /// Item 5. - /// Item 6. - /// Item 7. - /// Item 8. - /// Item 9. - /// Item 10. - /// Item 11. - /// Item 12. - /// Item 13. - /// Item 14. - /// Item 15. - public ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); - BaseInStructure* itemPtr = Item1Ptr; - item1.StructureType(); - Marshal.StructureToPtr(item1, (nint)itemPtr, false); - HeadPtr->PNext = itemPtr; - itemPtr = Item2Ptr; - item2.StructureType(); - Marshal.StructureToPtr(item2, (nint)itemPtr, false); - Item1Ptr->PNext = itemPtr; - itemPtr = Item3Ptr; - item3.StructureType(); - Marshal.StructureToPtr(item3, (nint)itemPtr, false); - Item2Ptr->PNext = itemPtr; - itemPtr = Item4Ptr; - item4.StructureType(); - Marshal.StructureToPtr(item4, (nint)itemPtr, false); - Item3Ptr->PNext = itemPtr; - itemPtr = Item5Ptr; - item5.StructureType(); - Marshal.StructureToPtr(item5, (nint)itemPtr, false); - Item4Ptr->PNext = itemPtr; - itemPtr = Item6Ptr; - item6.StructureType(); - Marshal.StructureToPtr(item6, (nint)itemPtr, false); - Item5Ptr->PNext = itemPtr; - itemPtr = Item7Ptr; - item7.StructureType(); - Marshal.StructureToPtr(item7, (nint)itemPtr, false); - Item6Ptr->PNext = itemPtr; - itemPtr = Item8Ptr; - item8.StructureType(); - Marshal.StructureToPtr(item8, (nint)itemPtr, false); - Item7Ptr->PNext = itemPtr; - itemPtr = Item9Ptr; - item9.StructureType(); - Marshal.StructureToPtr(item9, (nint)itemPtr, false); - Item8Ptr->PNext = itemPtr; - itemPtr = Item10Ptr; - item10.StructureType(); - Marshal.StructureToPtr(item10, (nint)itemPtr, false); - Item9Ptr->PNext = itemPtr; - itemPtr = Item11Ptr; - item11.StructureType(); - Marshal.StructureToPtr(item11, (nint)itemPtr, false); - Item10Ptr->PNext = itemPtr; - itemPtr = Item12Ptr; - item12.StructureType(); - Marshal.StructureToPtr(item12, (nint)itemPtr, false); - Item11Ptr->PNext = itemPtr; - itemPtr = Item13Ptr; - item13.StructureType(); - Marshal.StructureToPtr(item13, (nint)itemPtr, false); - Item12Ptr->PNext = itemPtr; - itemPtr = Item14Ptr; - item14.StructureType(); - Marshal.StructureToPtr(item14, (nint)itemPtr, false); - Item13Ptr->PNext = itemPtr; - itemPtr = Item15Ptr; - item15.StructureType(); - Marshal.StructureToPtr(item15, (nint)itemPtr, false); - Item14Ptr->PNext = itemPtr; - Item15Ptr->PNext = null; - } - - /// - /// Creates a new with 16 items from an existing unmanaged chain. - /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) - { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item1Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item1 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item2Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T2 item2 = default; - expectedStructureType = item2.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 2, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 3; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item2 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item2, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item3Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T3 item3 = default; - expectedStructureType = item3.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 3, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 4; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item3 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item3, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item4Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T4 item4 = default; - expectedStructureType = item4.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 4, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 5; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item4 = Unsafe.AsRef(existingPtr); - } - } - Marshal.StructureToPtr(item4, (nint) newPtr, false); - - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item5Offset); - newPtr = (BaseInStructure*)newPtr->PNext; - - T5 item5 = default; - expectedStructureType = item5.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 5, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 6; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item5 = Unsafe.AsRef(existingPtr); - } + var ptr = Item2Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item5, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item6Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item3Ptr => (BaseInStructure*) (_headPtr + Item3Offset); - T6 item6 = default; - expectedStructureType = item6.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 6, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 7; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item6 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #3 in the chain. + /// + public T3 Item3 + { + get => Unsafe.AsRef(Item3Ptr); + set + { + value.StructureType(); + var ptr = Item3Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item6, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item7Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item4Ptr => (BaseInStructure*) (_headPtr + Item4Offset); - T7 item7 = default; - expectedStructureType = item7.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 7, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 8; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item7 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #4 in the chain. + /// + public T4 Item4 + { + get => Unsafe.AsRef(Item4Ptr); + set + { + value.StructureType(); + var ptr = Item4Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item7, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item8Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item5Ptr => (BaseInStructure*) (_headPtr + Item5Offset); - T8 item8 = default; - expectedStructureType = item8.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 8, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 9; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item8 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #5 in the chain. + /// + public T5 Item5 + { + get => Unsafe.AsRef(Item5Ptr); + set + { + value.StructureType(); + var ptr = Item5Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item8, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item9Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item6Ptr => (BaseInStructure*) (_headPtr + Item6Offset); - T9 item9 = default; - expectedStructureType = item9.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 9, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 10; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item9 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #6 in the chain. + /// + public T6 Item6 + { + get => Unsafe.AsRef(Item6Ptr); + set + { + value.StructureType(); + var ptr = Item6Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item9, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item10Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item7Ptr => (BaseInStructure*) (_headPtr + Item7Offset); - T10 item10 = default; - expectedStructureType = item10.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 10, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 11; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item10 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #7 in the chain. + /// + public T7 Item7 + { + get => Unsafe.AsRef(Item7Ptr); + set + { + value.StructureType(); + var ptr = Item7Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item10, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item11Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item8Ptr => (BaseInStructure*) (_headPtr + Item8Offset); - T11 item11 = default; - expectedStructureType = item11.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 11, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 12; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item11 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #8 in the chain. + /// + public T8 Item8 + { + get => Unsafe.AsRef(Item8Ptr); + set + { + value.StructureType(); + var ptr = Item8Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item11, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item12Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item9Ptr => (BaseInStructure*) (_headPtr + Item9Offset); - T12 item12 = default; - expectedStructureType = item12.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 12, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 13; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item12 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #9 in the chain. + /// + public T9 Item9 + { + get => Unsafe.AsRef(Item9Ptr); + set + { + value.StructureType(); + var ptr = Item9Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item12, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item13Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item10Ptr => (BaseInStructure*) (_headPtr + Item10Offset); - T13 item13 = default; - expectedStructureType = item13.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 13, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 14; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item13 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #10 in the chain. + /// + public T10 Item10 + { + get => Unsafe.AsRef(Item10Ptr); + set + { + value.StructureType(); + var ptr = Item10Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item13, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item14Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item11Ptr => (BaseInStructure*) (_headPtr + Item11Offset); - T14 item14 = default; - expectedStructureType = item14.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 14, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 15; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - item14 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #11 in the chain. + /// + public T11 Item11 + { + get => Unsafe.AsRef(Item11Ptr); + set + { + value.StructureType(); + var ptr = Item11Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item14, (nint) newPtr, false); + } - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item15Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item12Ptr => (BaseInStructure*) (_headPtr + Item12Offset); - T15 item15 = default; - expectedStructureType = item15.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 15, expected length 16"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 16; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 16"); - existingPtr->PNext = null; - } - item15 = Unsafe.AsRef(existingPtr); - } + /// + /// Gets or sets item #12 in the chain. + /// + public T12 Item12 + { + get => Unsafe.AsRef(Item12Ptr); + set + { + value.StructureType(); + var ptr = Item12Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; } - Marshal.StructureToPtr(item15, (nint) newPtr, false); - - // Create string of errors - errors = errorBuilder.ToString().Trim(); } /// - /// Creates a new with 16 by copying this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Duplicate() + public BaseInStructure* Item13Ptr => (BaseInStructure*) (_headPtr + Item13Offset); + + /// + /// Gets or sets item #13 in the chain. + /// + public T13 Item13 { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); - ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); - ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); - ((BaseInStructure*)(newHeadPtr + Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item14Offset); - ((BaseInStructure*)(newHeadPtr + Item14Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item15Offset); - return new ManagedChain(newHeadPtr); + get => Unsafe.AsRef(Item13Ptr); + set + { + value.StructureType(); + var ptr = Item13Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 16 items, by appending - /// to the end of this chain. + /// Gets a pointer to the second item in the chain. /// - /// The chain to append to. - /// Item 15. - /// - /// Do not forget to dispose the chain if you are no longer using it. - /// - public ManagedChain(ManagedChain previous, T15 item15 = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item15Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item 15 - item15.StructureType(); - Marshal.StructureToPtr(item15, _headPtr + previousSize, false); + public BaseInStructure* Item14Ptr => (BaseInStructure*) (_headPtr + Item14Offset); - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); - ((BaseInStructure*)(_headPtr + Item1Offset))->PNext = (BaseInStructure*) (_headPtr + Item2Offset); - ((BaseInStructure*)(_headPtr + Item2Offset))->PNext = (BaseInStructure*) (_headPtr + Item3Offset); - ((BaseInStructure*)(_headPtr + Item3Offset))->PNext = (BaseInStructure*) (_headPtr + Item4Offset); - ((BaseInStructure*)(_headPtr + Item4Offset))->PNext = (BaseInStructure*) (_headPtr + Item5Offset); - ((BaseInStructure*)(_headPtr + Item5Offset))->PNext = (BaseInStructure*) (_headPtr + Item6Offset); - ((BaseInStructure*)(_headPtr + Item6Offset))->PNext = (BaseInStructure*) (_headPtr + Item7Offset); - ((BaseInStructure*)(_headPtr + Item7Offset))->PNext = (BaseInStructure*) (_headPtr + Item8Offset); - ((BaseInStructure*)(_headPtr + Item8Offset))->PNext = (BaseInStructure*) (_headPtr + Item9Offset); - ((BaseInStructure*)(_headPtr + Item9Offset))->PNext = (BaseInStructure*) (_headPtr + Item10Offset); - ((BaseInStructure*)(_headPtr + Item10Offset))->PNext = (BaseInStructure*) (_headPtr + Item11Offset); - ((BaseInStructure*)(_headPtr + Item11Offset))->PNext = (BaseInStructure*) (_headPtr + Item12Offset); - ((BaseInStructure*)(_headPtr + Item12Offset))->PNext = (BaseInStructure*) (_headPtr + Item13Offset); - ((BaseInStructure*)(_headPtr + Item13Offset))->PNext = (BaseInStructure*) (_headPtr + Item14Offset); - ((BaseInStructure*)(_headPtr + Item14Offset))->PNext = (BaseInStructure*) (_headPtr + Item15Offset); - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; + /// + /// Gets or sets item #14 in the chain. + /// + public T14 Item14 + { + get => Unsafe.AsRef(Item14Ptr); + set + { + value.StructureType(); + var ptr = Item14Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 15 items, by removing the last item - /// from this chain. + /// Gets a pointer to the second item in the chain. /// - /// - /// Do not forget to dispose this chain if you are no longer using it. - /// - public ManagedChain Truncate() + public BaseInStructure* Item15Ptr => (BaseInStructure*) (_headPtr + Item15Offset); + + /// + /// Gets or sets item #15 in the chain. + /// + public T15 Item15 { - return Truncate(out var _); + get => Unsafe.AsRef(Item15Ptr); + set + { + value.StructureType(); + var ptr = Item15Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } } /// - /// Creates a new with 15 items, by removing - /// from the end of this chain. + /// Creates a new with 16 items from an existing memory block. /// + /// The pointer to the head of the chain. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Callers are responsible for ensuring the size of the memory is correct. /// - public ManagedChain Truncate(out T15 item15) + internal ManagedChain(nint headPtr) { - item15 = Item15; + _headPtr = headPtr; + } - var newSize = MemorySize - Item15Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); - // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); - ((BaseInStructure*)(newHeadPtr + Item1Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item2Offset); - ((BaseInStructure*)(newHeadPtr + Item2Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item3Offset); - ((BaseInStructure*)(newHeadPtr + Item3Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item4Offset); - ((BaseInStructure*)(newHeadPtr + Item4Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item5Offset); - ((BaseInStructure*)(newHeadPtr + Item5Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item6Offset); - ((BaseInStructure*)(newHeadPtr + Item6Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item7Offset); - ((BaseInStructure*)(newHeadPtr + Item7Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item8Offset); - ((BaseInStructure*)(newHeadPtr + Item8Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item9Offset); - ((BaseInStructure*)(newHeadPtr + Item9Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item10Offset); - ((BaseInStructure*)(newHeadPtr + Item10Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item11Offset); - ((BaseInStructure*)(newHeadPtr + Item11Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item12Offset); - ((BaseInStructure*)(newHeadPtr + Item12Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item13Offset); - ((BaseInStructure*)(newHeadPtr + Item13Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item14Offset); - ((BaseInStructure*)(newHeadPtr + Item14Offset))->PNext = null; - return new ManagedChain(newHeadPtr); + /// + /// Creates a new with 16 items. + /// + /// The head of the chain. + /// Item 1. + /// Item 2. + /// Item 3. + /// Item 4. + /// Item 5. + /// Item 6. + /// Item 7. + /// Item 8. + /// Item 9. + /// Item 10. + /// Item 11. + /// Item 12. + /// Item 13. + /// Item 14. + /// Item 15. + internal ManagedChain(TChain head = default, T1 item1 = default, T2 item2 = default, T3 item3 = default, T4 item4 = default, T5 item5 = default, T6 item6 = default, T7 item7 = default, T8 item8 = default, T9 item9 = default, T10 item10 = default, T11 item11 = default, T12 item12 = default, T13 item13 = default, T14 item14 = default, T15 item15 = default) + : this(Marshal.AllocHGlobal(MemorySize)) + { + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); + var itemPtr = Item1Ptr; + item1.StructureType(); + Marshal.StructureToPtr(item1, (nint)itemPtr, false); + HeadPtr->PNext = itemPtr; + itemPtr = Item2Ptr; + item2.StructureType(); + Marshal.StructureToPtr(item2, (nint)itemPtr, false); + Item1Ptr->PNext = itemPtr; + itemPtr = Item3Ptr; + item3.StructureType(); + Marshal.StructureToPtr(item3, (nint)itemPtr, false); + Item2Ptr->PNext = itemPtr; + itemPtr = Item4Ptr; + item4.StructureType(); + Marshal.StructureToPtr(item4, (nint)itemPtr, false); + Item3Ptr->PNext = itemPtr; + itemPtr = Item5Ptr; + item5.StructureType(); + Marshal.StructureToPtr(item5, (nint)itemPtr, false); + Item4Ptr->PNext = itemPtr; + itemPtr = Item6Ptr; + item6.StructureType(); + Marshal.StructureToPtr(item6, (nint)itemPtr, false); + Item5Ptr->PNext = itemPtr; + itemPtr = Item7Ptr; + item7.StructureType(); + Marshal.StructureToPtr(item7, (nint)itemPtr, false); + Item6Ptr->PNext = itemPtr; + itemPtr = Item8Ptr; + item8.StructureType(); + Marshal.StructureToPtr(item8, (nint)itemPtr, false); + Item7Ptr->PNext = itemPtr; + itemPtr = Item9Ptr; + item9.StructureType(); + Marshal.StructureToPtr(item9, (nint)itemPtr, false); + Item8Ptr->PNext = itemPtr; + itemPtr = Item10Ptr; + item10.StructureType(); + Marshal.StructureToPtr(item10, (nint)itemPtr, false); + Item9Ptr->PNext = itemPtr; + itemPtr = Item11Ptr; + item11.StructureType(); + Marshal.StructureToPtr(item11, (nint)itemPtr, false); + Item10Ptr->PNext = itemPtr; + itemPtr = Item12Ptr; + item12.StructureType(); + Marshal.StructureToPtr(item12, (nint)itemPtr, false); + Item11Ptr->PNext = itemPtr; + itemPtr = Item13Ptr; + item13.StructureType(); + Marshal.StructureToPtr(item13, (nint)itemPtr, false); + Item12Ptr->PNext = itemPtr; + itemPtr = Item14Ptr; + item14.StructureType(); + Marshal.StructureToPtr(item14, (nint)itemPtr, false); + Item13Ptr->PNext = itemPtr; + itemPtr = Item15Ptr; + item15.StructureType(); + Marshal.StructureToPtr(item15, (nint)itemPtr, false); + Item14Ptr->PNext = itemPtr; + Item15Ptr->PNext = null; } /// @@ -12503,6 +18935,207 @@ public override IChainable this[int index] _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item12Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item13Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item14Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item15Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(", "); + sb.Append((object) Item8); + sb.Append(", "); + sb.Append((object) Item9); + sb.Append(", "); + sb.Append((object) Item10); + sb.Append(", "); + sb.Append((object) Item11); + sb.Append(", "); + sb.Append((object) Item12); + sb.Append(", "); + sb.Append((object) Item13); + sb.Append(", "); + sb.Append((object) Item14); + sb.Append(", "); + sb.Append((object) Item15); + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt index 7b072af330..9e6777b740 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt @@ -93,20 +93,47 @@ } return builder.ToString(); } + + string ConstraintListLoose(int index, string prefix) + { + var builder = new StringBuilder(prefix); + builder.Append("where TChain : struct, IChainable"); + for (var i = 1; i < index; i++) + { + builder + .AppendLine() + .Append(prefix) + .Append("where T") + .Append(i) + .Append(" : struct, IChainable"); + } + return builder.ToString(); + } #> // ReSharper disable StaticMemberInGenericType +#pragma warning disable CS0659, CS0660, CS0661 using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; /// -/// Static class for creating Managed Chains. +/// Base class for all Managed Chains. /// -public abstract class ManagedChain : IReadOnlyList, IDisposable +public abstract unsafe class ManagedChain : IReadOnlyList, IDisposable { + /// + /// Gets a pointer to the current head. + /// + public abstract BaseInStructure* HeadPtr { get; } + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public abstract int Size { get; } + /// public abstract IEnumerator GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() @@ -120,6 +147,19 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable /// public abstract IChainable this[int index] { get; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) + { + return !ReferenceEquals(null, obj) && + (ReferenceEquals(this, obj) || obj.GetType() == this.GetType() && MemoryEquals((ManagedChain) obj)); + } + + /// + /// Compares the supplied memory block with this one. + /// + protected abstract bool MemoryEquals(ManagedChain other); + /// public abstract void Dispose(); @@ -127,30 +167,37 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable for (var i = 1; i <= maximumItems; i++) { var tList = TypeList(i); + var pDocs = ParameterDocs(i, " /// "); + var pTypeDocs = ParameterTypeDocs(i, " /// "); + var constraints = ConstraintList(i, " "); + var constraintsLoose = ConstraintListLoose(i, " "); #> /// /// Creates a new with <#= i #> items. /// -<#= ParameterDocs(i, " /// ") #> -<#= ParameterTypeDocs(i, " /// ") #> +<#= pDocs #> +<#= pTypeDocs #> /// A new with <#= i #> items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedChain<<#= tList #>> Create<<#= tList #>>(<#= ParamList(i) #>) -<#= ConstraintList(i, " ") #> - { - return new(<#= ArgList(i) #>); - } +<#= constraints #> + => new(<#= ArgList(i) #>); /// - /// Loads a new with <#= i #> items from an existing unmanaged chain. + /// Creates a new with <#= i #> items. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. +<#= pDocs #> +<#= pTypeDocs #> /// A new with <#= i #> items. - public static ManagedChain<<#= tList #>> Load<<#= tList #>>(out string errors, TChain chain) -<#= ConstraintList(i, " ") #> - { - return new(out errors, chain); - } + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain<<#= tList #>> CreateAny<<#= tList #>>(<#= ParamList(i) #>) +<#= constraintsLoose #> + => new(<#= ArgList(i) #>); /// /// Loads a new with <#= i #> items from an existing unmanaged chain, @@ -158,152 +205,57 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable /// /// The unmanaged chain to use as the basis of this chain. /// A new with <#= i #> items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedChain<<#= tList #>> Load<<#= tList #>>(TChain chain) -<#= ConstraintList(i, " ") #> - { - return new(out var _, chain); - } - -<# - } // for (var i = 1; i <= maximumItems; i++) -#> -} -<# - for (var i = 1; i <= maximumItems; i++) - { - var tList = TypeList(i); -#> - -/// -/// A safely manages the pointers of a managed structure chain. -/// -<#= ParameterTypeDocs(i, "/// ") #> -public unsafe class ManagedChain<<#= tList #>> : ManagedChain -<#= ConstraintList(i, " ") #> -{ - /// - /// Gets the size (in bytes) of the head structure. - /// - public static readonly int HeadSize = Marshal.SizeOf(); -<# - for (var j = 1; j < i; j++) - { -#> - - /// - /// Gets the offset to the start of . - /// - public static readonly int Item<#= j #>Offset = <#= j == 1 ? "HeadSize" : $"Item{j - 1}Offset + Item{j - 1}Size" #>; - - /// - /// Gets the size (in bytes) of the Item 1. - /// - public static readonly int Item<#= j #>Size = Marshal.SizeOf>(); -<# - } // for (int j = 1; j < i; j++) { -#> - - /// - /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. - /// - public static readonly int MemorySize = <#= i == 1 ? "HeadSize" : $"Item{i - 1}Offset + Item{i - 1}Size" #>; - - private nint _headPtr; - - /// - /// Gets a pointer to the current head. - /// - public BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; - - /// - /// Gets or sets the head of the chain. - /// - public TChain Head - { - get => Unsafe.AsRef((BaseInStructure*) _headPtr); - set - { - value.StructureType(); - var ptr = (BaseInStructure*) _headPtr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, _headPtr, true); - ptr->PNext = nextPtr; - } - } -<# - for (var j = 1; j < i; j++) - { -#> - - /// - /// Gets a pointer to the second item in the chain. - /// - public BaseInStructure* Item<#= j #>Ptr => (BaseInStructure*) (_headPtr + Item<#= j #>Offset); - - /// - /// Gets or sets item #<#= j #> in the chain. - /// - public T<#= j #> Item<#= j #> - { - get => Unsafe.AsRef>(Item<#= j #>Ptr); - set - { - value.StructureType(); - var ptr = Item<#= j #>Ptr; - var nextPtr = ptr->PNext; - Marshal.StructureToPtr(value, (nint)ptr, true); - ptr->PNext = nextPtr; - } - } -<# - } // for (int j = 1; j < i; j++) { -#> +<#= constraints #> + => LoadAny<<#= tList #>>(out var _, chain); /// - /// Creates a new with <#= i #> items from an existing memory block. + /// Loads a new with <#= i #> items from an existing unmanaged chain, + /// ignoring any errors. /// - /// The pointer to the head of the chain.. - /// - /// Callers are responsible for ensuring the size of the memory is correct. - /// - internal ManagedChain(nint headPtr) - { - _headPtr = headPtr; - } + /// The unmanaged chain to use as the basis of this chain. + /// A new with <#= i #> items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain<<#= tList #>> LoadAny<<#= tList #>>(TChain chain) +<#= constraintsLoose #> + => LoadAny<<#= tList #>>(out var _, chain); /// - /// Creates a new with <#= i #> items. + /// Loads a new with <#= i #> items from an existing unmanaged chain. /// -<#= ParameterDocs(i, " /// ") #> - public ManagedChain(<#= ParamList(i) #>) - : this(Marshal.AllocHGlobal(MemorySize)) - { - head.StructureType(); - Marshal.StructureToPtr(head, _headPtr, false); -<# - for (var j = 1; j < i; j++) - { -#> - <#= j == 1 ? "BaseInStructure* " : "" #>itemPtr = Item<#= j #>Ptr; - item<#= j #>.StructureType(); - Marshal.StructureToPtr(item<#= j #>, (nint)itemPtr, false); - <#= j == 1 ? "HeadPtr" : $"Item{j - 1}Ptr" #>->PNext = itemPtr; -<# - } // for (int j = 1; j < i; j++) { -#> - <#= i == 1 ? "HeadPtr" : $"Item{i - 1}Ptr" #>->PNext = null; - } + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with <#= i #> items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain<<#= tList #>> Load<<#= tList #>>(out string errors, TChain chain) +<#= constraints #> + => LoadAny<<#= tList #>>(out errors, chain); /// - /// Creates a new with <#= i #> items from an existing unmanaged chain. + /// Loads a new with <#= i #> items from an existing unmanaged chain. /// /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) + /// A new with <#= i #> items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain<<#= tList #>> LoadAny<<#= tList #>>(out string errors, TChain chain) +<#= constraintsLoose #> { + var size = ManagedChain<<#= tList #>>.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); + Marshal.StructureToPtr(chain, newHeadPtr, false); <# if (i == 1) { @@ -314,17 +266,17 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain else { #> - StringBuilder errorBuilder = new StringBuilder(); + var errorBuilder = new StringBuilder(); var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); - var newPtr = (BaseInStructure*) _headPtr; + var newPtr = (BaseInStructure*) newHeadPtr; <# for (var j = 1; j < i; j++) { #> - existingPtr = (BaseInStructure*)existingPtr->PNext; - newPtr->PNext = (BaseInStructure*)(_headPtr + Item<#= j #>Offset); - newPtr = (BaseInStructure*)newPtr->PNext; + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain<<#= tList #>>.Item<#= j #>Offset); + newPtr = newPtr->PNext; T<#= j #> item<#= j #> = default; <#= j == 1 ? "var " : "" #>expectedStructureType = item<#= j #>.StructureType(); @@ -362,25 +314,70 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain <# } // if (i == 1) {} else {... #> + return new ManagedChain<<#= tList #>>(newHeadPtr); } +<# + } // for (var i = 1; i <= maximumItems; i++) +#> +} + +/// +/// Static class providing extension methods for manipulating managed chains. +/// +/// The `Any` versions of chain methods do not validate that items belong in the chain, this is +/// useful for situations where the specification does not indicate required chain constraints. You should generally +/// try to use the none `Any` version in preference. +public static unsafe class ManagedChainExtensions +{ +<# + for (var i = 1; i <= maximumItems; i++) + { + var tList = TypeList(i); + var pTypeDocs = ParameterTypeDocs(i, " /// "); + var constraints = ConstraintList(i, " "); + var constraintsLoose = ConstraintListLoose(i, " "); +#> /// - /// Creates a new with <#= i #> by copying this chain. + /// Creates a new with <#= i #> by copying the . /// + /// The chain. +<#= pTypeDocs #> /// /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain<<#= tList #>> Duplicate() + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain<<#= tList #>> Duplicate<<#= tList #>>(this ManagedChain<<#= tList #>> chain) +<#= constraints #> + => chain.DuplicateAny(); + + /// + /// Creates a new with <#= i #> by copying the . + /// + /// The chain. +<#= pTypeDocs #> + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain<<#= tList #>> DuplicateAny<<#= tList #>>(this ManagedChain<<#= tList #>> chain) +<#= constraintsLoose #> { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); + var size = ManagedChain<<#= tList #>>.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); <# if (i > 1) { #> // Update all pointers - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain<<#= tList #>>.Item1Offset); <# } // if (i > 1) #> @@ -388,127 +385,333 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain for (var j = 2; j < i; j++) { #> - ((BaseInStructure*)(newHeadPtr + Item<#= j - 1 #>Offset))->PNext = (BaseInStructure*) (newHeadPtr + Item<#= j #>Offset); + ((BaseInStructure*)(newHeadPtr + ManagedChain<<#= tList #>>.Item<#= j - 1 #>Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain<<#= tList #>>.Item<#= j #>Offset); <# } // for (int j = 1; j < i; j++) { #> return new ManagedChain<<#= tList #>>(newHeadPtr); } + <# if (i > 1) { var shortTList = TypeList(i - 1); #> - /// - /// Creates a new with <#= i #> items, by appending - /// to the end of this chain. + /// Creates a new with <#= i - 1 #> items, by removing the last item + /// from the . /// - /// The chain to append to. - /// Item <#= i - 1 #>. + /// The chain. +<#= pTypeDocs #> /// - /// Do not forget to dispose the chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain(ManagedChain<<#= shortTList #>> previous, T<#= i - 1 #> item<#= i - 1 #> = default) - : this(Marshal.AllocHGlobal(MemorySize)) - { - var previousSize = MemorySize - Item<#= i - 1 #>Size; - // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); - - // Append item <#= i - 1 #> - item<#= i - 1 #>.StructureType(); - Marshal.StructureToPtr(item<#= i - 1 #>, _headPtr + previousSize, false); - - // Update all pointers - ((BaseInStructure*)_headPtr)->PNext = (BaseInStructure*) (_headPtr + Item1Offset); -<# - for (var j = 2; j < i; j++) - { -#> - ((BaseInStructure*)(_headPtr + Item<#= j - 1 #>Offset))->PNext = (BaseInStructure*) (_headPtr + Item<#= j #>Offset); -<# - } // for (int j = 1; j < i; j++) { -#> - ((BaseInStructure*)(_headPtr + previousSize))->PNext = null; - } + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain<<#= shortTList #>> Truncate<<#= tList #>>(this ManagedChain<<#= tList #>> chain) +<#= constraints #> + => chain.TruncateAny(out var _); /// /// Creates a new with <#= i - 1 #> items, by removing the last item - /// from this chain. + /// from the . + /// + /// The chain. +<#= pTypeDocs #> + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain<<#= shortTList #>> TruncateAny<<#= tList #>>(this ManagedChain<<#= tList #>> chain) +<#= constraintsLoose #> + => chain.TruncateAny(out var _); + + /// + /// Creates a new with <#= i - 1 #> items, by removing + /// from the end of the . /// + /// The chain. + /// The item removed from the . +<#= pTypeDocs #> /// /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain<<#= shortTList #>> Truncate() - { - return Truncate(out var _); - } + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain<<#= shortTList #>> Truncate<<#= tList #>>(this ManagedChain<<#= tList #>> chain, out T<#= i - 1 #> item<#= i - 1 #>) +<#= constraints #> + => chain.TruncateAny(out item<#= i - 1 #>); /// /// Creates a new with <#= i - 1 #> items, by removing - /// from the end of this chain. + /// from the end of the . /// + /// The chain. + /// The item removed from the . +<#= pTypeDocs #> /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. /// - public ManagedChain<<#= shortTList #>> Truncate(out T<#= i - 1 #> item<#= i - 1 #>) + /// + /// + /// + public static ManagedChain<<#= shortTList #>> TruncateAny<<#= tList #>>(this ManagedChain<<#= tList #>> chain, out T<#= i - 1 #> item<#= i - 1 #>) +<#= constraintsLoose #> { - item<#= i - 1 #> = Item<#= i - 1 #>; + // Retrieve last item. + item<#= i - 1 #> = chain.Item<#= i - 1 #>; - var newSize = MemorySize - Item<#= i - 1 #>Size; + var newSize = ManagedChain<<#= tList #>>.MemorySize - ManagedChain<<#= tList #>>.Item<#= i - 1 #>Size; var newHeadPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); // Update all pointers <# if (i > 2) { #> - ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + Item1Offset); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain<<#= tList #>>.Item1Offset); <# for (var j = 2; j < i; j++) { #> - ((BaseInStructure*)(newHeadPtr + Item<#= j - 1 #>Offset))->PNext = <#= j == i -1 ? "null" : $"(BaseInStructure*) (newHeadPtr + Item{j}Offset)"#>; + ((BaseInStructure*)(newHeadPtr + ManagedChain<<#= tList #>>.Item<#= j - 1 #>Offset))->PNext = <#= + j == i - 1 + ? "null" + : $"(BaseInStructure*) (newHeadPtr + ManagedChain<{tList}>.Item{j}Offset)" #>; <# } // for (int j = 1; j < i - 1; j++) } else // if (i > 1) { - #> +#> ((BaseInStructure*)newHeadPtr)->PNext = null; <# } #> return new ManagedChain<<#= shortTList #>>(newHeadPtr); } + <# - } // if (i > 1) + } // (i > 1) if (i < maximumItems) { var bigTList = TypeList(i + 1); + var bigPTypeDocs = ParameterTypeDocs(i + 1, " /// "); + var bigConstraints = ConstraintList(i + 1, " "); + var bigConstraintsLoose = ConstraintListLoose(i + 1, " "); #> + /// + /// Creates a new with <#= i + 1 #> items, by appending to + /// the end of the . + /// + /// The chain. + /// The item to append. +<#= bigPTypeDocs #> + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + public static ManagedChain<<#= bigTList #>> Add<<#= bigTList #>>(this ManagedChain<<#= tList #>> chain, T<#= i #> item<#= i #> = default) +<#= bigConstraints #> + => chain.AddAny(item<#= i #>); /// /// Creates a new with <#= i + 1 #> items, by appending to - /// the end of this chain. + /// the end of the . /// - /// Item <#= i #>. - /// Type of Item <#= i #> + /// The chain. + /// The item to append. +<#= bigPTypeDocs #> /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. /// - public ManagedChain<<#= bigTList #>> Append>(T<#= i #> item<#= i #> = default) - where T<#= i #>: struct, IExtendsChain + /// + public static ManagedChain<<#= bigTList #>> AddAny<<#= bigTList #>>(this ManagedChain<<#= tList #>> chain, T<#= i #> item<#= i #> = default) +<#= bigConstraintsLoose #> { - return new ManagedChain<<#= tList #>, T<#= i #>>(this, item<#= i #>); + var previousSize = ManagedChain<<#= tList #>>.MemorySize; + var newSize = ManagedChain<<#= bigTList #>>.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); + + // Append item <#= i - 1 #> + item<#= i #>.StructureType(); + Marshal.StructureToPtr(item<#= i #>, newHeadPtr + previousSize, false); + + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain<<#= bigTList #>>.Item1Offset); +<# + for (var j = 1; j < i; j++) + { +#> + ((BaseInStructure*)(newHeadPtr + ManagedChain<<#= bigTList #>>.Item<#= j #>Offset))->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain<<#= bigTList #>>.Item<#= j + 1 #>Offset); +<# + } // for (int j = 1; j < i; j++) { +#> + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain<<#= bigTList #>>(newHeadPtr); } + <# } // if (i < maximumItems) + } // for (var i = 1; i <= maximumItems; i++) +#> +} +<# + for (var i = 1; i <= maximumItems; i++) + { + var tList = TypeList(i); + var pDocs = ParameterDocs(i, " /// "); +#> + +/// +/// A safely manages the pointers of a managed structure chain. +/// +<#= ParameterTypeDocs(i, "/// ") #> +public unsafe sealed class ManagedChain<<#= tList #>> : ManagedChain, IEquatable>> +<#= ConstraintListLoose(i, " ") #> +{ + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + + /// + /// Gets the size (in bytes) of the head structure. + /// + public static readonly int HeadSize = Marshal.SizeOf(); +<# + for (var j = 1; j < i; j++) + { +#> + + /// + /// Gets the offset to the start of . + /// + public static readonly int Item<#= j #>Offset = <#= j == 1 ? "HeadSize" : $"Item{j - 1}Offset + Item{j - 1}Size" #>; + + /// + /// Gets the size (in bytes) of the Item 1. + /// + public static readonly int Item<#= j #>Size = Marshal.SizeOf>(); +<# + } // for (int j = 1; j < i; j++) { #> + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public static readonly int MemorySize = <#= i == 1 ? "HeadSize" : $"Item{i - 1}Offset + Item{i - 1}Size" #>; + + /// + public override int Size => MemorySize; + + private nint _headPtr; + + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; + + /// + /// Gets or sets the head of the chain. + /// + public TChain Head + { + get => Unsafe.AsRef((BaseInStructure*) _headPtr); + set + { + value.StructureType(); + var ptr = (BaseInStructure*) _headPtr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, _headPtr, true); + ptr->PNext = nextPtr; + } + } +<# + for (var j = 1; j < i; j++) + { +#> + + /// + /// Gets a pointer to the second item in the chain. + /// + public BaseInStructure* Item<#= j #>Ptr => (BaseInStructure*) (_headPtr + Item<#= j #>Offset); + + /// + /// Gets or sets item #<#= j #> in the chain. + /// + public T<#= j #> Item<#= j #> + { + get => Unsafe.AsRef>(Item<#= j #>Ptr); + set + { + value.StructureType(); + var ptr = Item<#= j #>Ptr; + var nextPtr = ptr->PNext; + Marshal.StructureToPtr(value, (nint)ptr, true); + ptr->PNext = nextPtr; + } + } +<# + } // for (int j = 1; j < i; j++) { +#> + + /// + /// Creates a new with <#= i #> items from an existing memory block. + /// + /// The pointer to the head of the chain. + /// + /// Callers are responsible for ensuring the size of the memory is correct. + /// + internal ManagedChain(nint headPtr) + { + _headPtr = headPtr; + } + + /// + /// Creates a new with <#= i #> items. + /// +<#= pDocs #> + internal ManagedChain(<#= ParamList(i) #>) + : this(Marshal.AllocHGlobal(MemorySize)) + { + head.StructureType(); + Marshal.StructureToPtr(head, _headPtr, false); +<# + for (var j = 1; j < i; j++) + { +#> + <#= j == 1 ? "var " : "" #>itemPtr = Item<#= j #>Ptr; + item<#= j #>.StructureType(); + Marshal.StructureToPtr(item<#= j #>, (nint)itemPtr, false); + <#= j == 1 ? "HeadPtr" : $"Item{j - 1}Ptr" #>->PNext = itemPtr; +<# + } // for (int j = 1; j < i; j++) { +#> + <#= i == 1 ? "HeadPtr" : $"Item{i - 1}Ptr" #>->PNext = null; + } + /// public override IEnumerator GetEnumerator() { @@ -542,10 +745,85 @@ public unsafe class ManagedChain<<#= tList #>> : ManagedChain _ => throw new IndexOutOfRangeException() }; + /// + /// Compares the supplied memory block with this one, ignoring the structure headers. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) + { + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; +<# + for (var j = 1; j < i; j++) + { +#> + + start += length; + length = Item<#=j#>Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; +<# + } // for (int j = 1; j < i; j++) { +#> + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain<<#=tList#>> other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain<<#=tList#>> left, ManagedChain<<#=tList#>> right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain<<#=tList#>> left, ManagedChain<<#=tList#>> right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head);<# + for (var j = 1; j < i; j++) + { +#> + sb.Append(", "); + sb.Append((object) Item<#= j #>); +<# +} // for (int j = 1; j < i; j++) { +#> + sb.Append(")"); + return sb.ToString(); + } + /// /// Deconstructs this chain. /// -<#= ParameterDocs(i, " /// ") #> +<#= pDocs #> public void Deconstruct(out TChain head<# for (var j = 1; j < i; j++) { diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs index c642f30156..ea33002ba1 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceAccelerationStructureFeaturesKhr.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; public struct PhysicalDeviceAccelerationStructureFeaturesKhr : IExtendsChain, diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs index f370c44dc0..baaf642e87 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceDescriptorIndexingFeatures.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; public struct PhysicalDeviceDescriptorIndexingFeatures : IExtendsChain, diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures.cs index d38a0d2e30..cecb0b3267 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; public struct PhysicalDeviceFeatures { diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs index 0f3bc822ff..b5fe21e56e 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PhysicalDeviceFeatures2.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; public struct PhysicalDeviceFeatures2 : IChainStart, diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj index 79d8733662..9762caf80c 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/PrototypeStructChaining.csproj @@ -4,9 +4,8 @@ netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0 10 enable - enable true - Silk.Net.Vulkan + Silk.NET.Vulkan diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/StructureType.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/StructureType.cs index 28a3e988f7..f56cee31b8 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/StructureType.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/StructureType.cs @@ -1,4 +1,4 @@ -namespace Silk.Net.Vulkan; +namespace Silk.NET.Vulkan; public enum StructureType { From aebe0d25b2952cd38ffcb478b807131c115a6c86 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Sun, 14 Nov 2021 09:17:58 +0000 Subject: [PATCH 33/34] feat: Added `GetHashCode` implementation This is a proposed implementation that only checks the start of the payload. We may change this to check the full payload Also updated the proposals to match the new `Any` functionality. --- ...Struct Chaining - #2 Unmanaged Chaining.md | 2 +- ...n Struct Chaining - #3 Managed Chaining.md | 688 ++++++-- .../TestManagedChains.cs | 57 + .../PrototypeStructChaining/IChainable.cs | 3 + .../ManagedChain.gen.cs | 1417 ++++++++++++++++- .../ManagedChain.gen.tt | 53 + 6 files changed, 2014 insertions(+), 206 deletions(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md index 983c501d2b..35f13a7d9b 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #2 Unmanaged Chaining.md @@ -147,7 +147,7 @@ To be discussed: The proposal provides for the following usages. Note that where an `Any` extension method is mentioned, it is identical to the non-`Any` version (e.g. `AddNext` and `AddNextAny` are equivalent), save that the `Any` version does not -constrain the types to those associated with a defined chain. +constrain the types to those associated with a defined chain, instead types only need to be `IChainable`. ### Chain Building diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md index 86f6456027..abb1f84939 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md @@ -17,7 +17,8 @@ performance. However, many consumers are uncomfortable with pointers, and are especially prone to introducing bugs when placing structs onto the heap. This proposal provides a convenient `ManagedChain` class, and multiple -descendent `ManagedChain` (similar to the `System.Tuple` classes) classes to safely fix the structures in memory and prevent pointer bugs. +descendent `ManagedChain` (similar to the `System.Tuple` classes) classes to safely fix the structures +in memory and prevent pointer bugs. Whenever a structure is loaded into the `ManagedChain` its `SType` and `PNext` are forced to be correct, preventing errors. Structures can be replaced at any time, and will be inserted efficiently into the chain as an O(1) operation. @@ -46,6 +47,9 @@ errors. Structures can be replaced at any time, and will be inserted efficiently - The structure accessors return a copy of the structures, and always correct the `SType` and `PNext` on input. Even though the `PNext` values are exposed there is no way to modify them from outside the class, guaranteeing their safety. +- The managed chains implement `IEquatable`, allowing two chains with identical content to be efficiently compared ( + ignoring the `PNext` pointers, but already being confident the `SType` and ordering is correct). They also implement + the equality operator overloads, and `GetHashCode`. Open questions: @@ -62,6 +66,9 @@ Open questions: found in the unmanaged chain, no matter at what position they are found. This is not entirely unreasonable as the order of chains (after the start) is not fixed in Vulkan, and it will allow importing existing chains where the order doesn't matter. +- `GetHasCode` only includes the `SType` and, at most, the first 8 bytes of the payload, for speed. This is because a + HashCode only needs to generate reasonable separation, but does not need to be unique. It is possible, to hash the + entire memory block if desired, though at slightly worse performance. - Similar to `Append` and `Truncate` we could also add `Insert` and `Remove` methods, though slightly more complex, as we'd have to generate multiples of each, it is not difficult to do, for example: @@ -85,16 +92,31 @@ pubilc class ManagedCache ... { # Usage -### Creation +## The Any versions + +As with unmanaged chains, the managed chains system includes `Any` versions of all methods. In fact, +the `ManagedChain` constraints are 'loose', that is they only require types to be `IChainable` rather than +requiring the stricter constraints that prevent unrelated chain elements being added, or used as the start of a chain. + +With the exception of the setters on chain items, you cannot manipulate a chain save through the static methods, and the +preferred versions do include the tighter constraints. + +## Instance-Based Methods + +### Creation (Create/CreateAny) The following will create a chain starting with `PhysicalDeviceFeatures2`, pointing to `PhysicalDeviceDescriptorIndexingFeatures` and finishing with a `PhysicalDeviceAccelerationStructureFeaturesKHR` structure: ```csharp -using var chain = new ManagedChain(); - +using var chain = ManagedChain.Create + ( + default(PhysicalDeviceFeatures2), + default(PhysicalDeviceDescriptorIndexingFeatures), + default(PhysicalDeviceAccelerationStructureFeaturesKhr) + ); + // Ensure all STypes set correctly Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); @@ -108,7 +130,7 @@ Assert.Equal((nint) 0, (nint) chain.Item2.PNext); The structures are held in unmanaged memory, preventing movement by the GC, and ensuring that the pointers remain fixed. -You can also use the `ManagedChain.Create(...)` static methods to create `ManagedChain`s, e.g.: +You can also use specify the generic types directly, e.g.: ```csharp using var chain = ManagedChain.Create< @@ -117,19 +139,10 @@ using var chain = ManagedChain.Create< PhysicalDeviceDescriptorIndexingFeatures>(); ``` -or, using generic type inference: - -```csharp -using var chain = ManagedChain.Create( - new DeviceCreateInfo { Flags = 1U }, - default(PhysicalDeviceFeatures2), - default(PhysicalDeviceDescriptorIndexingFeatures) -); -``` - -### Modifying values +### Modifying values (Head/Item# properties) -We can easily modify any value in the `ManagedChain`, and it will maintain the pointers automatically, e.g.: +We can easily modify any value in the `ManagedChain`, and it will maintain the pointers automatically. You do this using +the `Head` property, or one of the `Item#` properties (e.g. `Item1`), for example: ```csharp using var chain = ManagedChain.Create< @@ -169,13 +182,15 @@ Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); **Note** When we update any item in the chain it overwrites the existing memory, so the pointers remain fixed. It also ensures the `PNext` value pointing to it is maintained. -### Appending to a chain +## Extension Methods + +### Appending to a chain (Append/AppendAny) You can call `Append` on a `ManagedChain` (of length < 16) to efficiently create a new, larger, `ManagedChain` with a new item appended to the end, e.g: ```csharp -using var chain = new ManagedChain( +using var chain = ManagedChain.Create( item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true}); // The new chain, will efficiently copy the old chain and append a new structure to the end @@ -190,9 +205,10 @@ Assert.True(newChain.Item1.ShaderInputAttachmentArrayDynamicIndexing); finished with, when using the `Append` method you will produce a new `ManagedChain` and should not forget to dispose the original if it is no longer needed. -### Truncate +### Truncating (Truncate/TruncateAny) Similarly, you can `Truncate` a chain (of length > 1) to get an instance of a smaller chain: + ```csharp using var chain = ManagedChain.Create(); using var chain2 = chain.Append(); @@ -204,16 +220,23 @@ Assert.Equal(2, chain2.Count); Assert.Equal(1, chain3.Count); ``` -### Duplicate +### Duplication (Duplicate/DuplicateAny) You can efficiently duplicate a managed chain by calling Duplicate on it: + ```csharp -using var chain = new ManagedChain(); using var copy = chain.Duplicate(); + +// Test equality +Assert.Equal(chain, copy); +Assert.True(chain == copy); ``` -### Loading from an unmanaged chain +**Note** The `copy` is 'equal' to the `chain` until you modify it's contents. + +### Loading from an unmanaged chain (Load/LoadAny) If you have created an unmanaged chain and would like to load that into a `ManagedChain` you can use one of the `ManagedChain.Load` methods: @@ -284,6 +307,8 @@ Assert.True(managedChain.Item2.ShaderInputAttachmentArrayDynamicIndexing); Notice that the above form uses the equivalent constructor as an alternative to the `Load` method. There is no equivalent constructor to `Load(TChain)` as that would be ambiguous. +## Additional interfaces + ### IReadOnlyList All the fully generic `ManageChain` types extend `ManagedChain` which implements `IDisposable` @@ -311,6 +336,11 @@ Assert.IsType(structures[1]); Assert.IsType(structures[2]); ``` +### Equality (IEquatable<T>) + +ll the fully generic `ManageChain` types implement the corresponding `IEquatable>` +interface, and equality operators. As well as `GetHashCode`. + ### Deconstruction Each `ManageChain` has a corresponding deconstructor for convenience, e.g.: @@ -327,7 +357,7 @@ Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, indexingFea Assert.Equal(StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeaturesKhr.SType); ``` -### Disposal +### Disposal (IDisposable) As each `ManagedChain` holds the underlying structures in unmanaged memory (to prevent them being moved and their pointers being invalidated), then it is critical you dispose them; either by calling `Dispose()` or by using a `using` @@ -341,8 +371,22 @@ The `ManagedChain`, non-generic abstract base class provides an abstract impleme and defines static `Create` and `Load` methods for each size of chain. ```csharp -public abstract class ManagedChain : IReadOnlyList, IDisposable + +/// +/// Base class for all Managed Chains. +/// +public abstract unsafe class ManagedChain : IReadOnlyList, IDisposable { + /// + /// Gets a pointer to the current head. + /// + public abstract BaseInStructure* HeadPtr { get; } + + /// + /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. + /// + public abstract int Size { get; } + /// public abstract IEnumerator GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() @@ -356,9 +400,40 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable /// public abstract IChainable this[int index] { get; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) + { + return !ReferenceEquals(null, obj) && + (ReferenceEquals(this, obj) || obj.GetType() == this.GetType() && MemoryEquals((ManagedChain) obj)); + } + + /// + /// Compares the supplied memory block with this one. + /// + protected abstract bool MemoryEquals(ManagedChain other); + /// public abstract void Dispose(); + /// + /// Combines a hashcode with the first part of a slice. + /// + /// + /// + /// + protected static void CombineHash(ref int hashCode, ReadOnlySpan slice) => + hashCode = slice.Length switch + { + < 2 => HashCode.Combine(hashCode, slice[0]), + < 4 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), + < 8 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), + _ => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]) + }; + + // Skipping methods for `ManagedChain{TChain}` to show more completed example + ... + /// /// Creates a new with 2 items. /// @@ -367,12 +442,59 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable /// The chain type /// Type of Item 1. /// A new with 2 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedChain Create(TChain head = default, T1 item1 = default) where TChain : struct, IChainStart where T1 : struct, IExtendsChain - { - return new(head, item1); - } + => new(head, item1); + + /// + /// Creates a new with 2 items. + /// + /// The head of the chain. + /// Item 1. + /// The chain type + /// Type of Item 1. + /// A new with 2 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain CreateAny(TChain head = default, T1 item1 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable + => new(head, item1); + + /// + /// Loads a new with 2 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 2 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Load(TChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + => LoadAny(out var _, chain); + + /// + /// Loads a new with 2 items from an existing unmanaged chain, + /// ignoring any errors. + /// + /// The unmanaged chain to use as the basis of this chain. + /// A new with 2 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + => LoadAny(out var _, chain); /// /// Loads a new with 2 items from an existing unmanaged chain. @@ -380,11 +502,64 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable /// Any errors loading the chain. /// The unmanaged chain to use as the basis of this chain. /// A new with 2 items. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ManagedChain Load(out string errors, TChain chain) where TChain : struct, IChainStart where T1 : struct, IExtendsChain + => LoadAny(out errors, chain); + + /// + /// Loads a new with 2 items from an existing unmanaged chain. + /// + /// Any errors loading the chain. + /// The unmanaged chain to use as the basis of this chain. + /// A new with 2 items. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain LoadAny(out string errors, TChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable { - return new(out errors, chain); + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); + chain.StructureType(); + Marshal.StructureToPtr(chain, newHeadPtr, false); + var errorBuilder = new StringBuilder(); + var existingPtr = (BaseInStructure*) Unsafe.AsPointer(ref chain); + var newPtr = (BaseInStructure*) newHeadPtr; + + existingPtr = existingPtr->PNext; + newPtr->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + newPtr = newPtr->PNext; + + T1 item1 = default; + var expectedStructureType = item1.StructureType(); + if (existingPtr is null) { + errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); + } else { + if (existingPtr->SType != expectedStructureType) { + errorBuilder.Append("The unmanaged chain has a structure type ") + .Append(existingPtr->SType) + .Append(" at position 2; expected ") + .Append(expectedStructureType) + .AppendLine(); + } else { + if (existingPtr->PNext is not null) { + errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); + existingPtr->PNext = null; + } + item1 = Unsafe.AsRef(existingPtr); + } + } + Marshal.StructureToPtr(item1, (nint) newPtr, false); + + // Create string of errors + errors = errorBuilder.ToString().Trim(); + return new ManagedChain(newHeadPtr); } // Only showing one example of Create/Load methods @@ -397,16 +572,20 @@ public abstract class ManagedChain : IReadOnlyList, IDisposable A class is generated for each valid size of a chain, here is one example: ```csharp - /// /// A safely manages the pointers of a managed structure chain. /// /// The chain type /// Type of Item 1. -public unsafe class ManagedChain : ManagedChain - where TChain : struct, IChainStart - where T1 : struct, IExtendsChain +public unsafe sealed class ManagedChain : ManagedChain, IEquatable> + where TChain : struct, IChainable + where T1 : struct, IChainable { + /// + /// Gets the size (in bytes) of the default structure header. + /// + public static readonly int HeaderSize = Marshal.SizeOf(); + /// /// Gets the size (in bytes) of the head structure. /// @@ -426,24 +605,25 @@ public unsafe class ManagedChain : ManagedChain /// Gets the total size (in bytes) of the unmanaged memory, managed by this chain. /// public static readonly int MemorySize = Item1Offset + Item1Size; - + + /// + public override int Size => MemorySize; + private nint _headPtr; - /// - /// Gets a pointer to the current head. - /// - public Chain* HeadPtr => (Chain*) _headPtr; + /// + public override BaseInStructure* HeadPtr => (BaseInStructure*) _headPtr; /// /// Gets or sets the head of the chain. /// public TChain Head { - get => Unsafe.AsRef((Chain*) _headPtr); + get => Unsafe.AsRef((BaseInStructure*) _headPtr); set { value.StructureType(); - var ptr = (Chain*) _headPtr; + var ptr = (BaseInStructure*) _headPtr; var nextPtr = ptr->PNext; Marshal.StructureToPtr(value, _headPtr, true); ptr->PNext = nextPtr; @@ -453,7 +633,7 @@ public unsafe class ManagedChain : ManagedChain /// /// Gets a pointer to the second item in the chain. /// - public Chain* Item1Ptr => (Chain*) (_headPtr + Item1Offset); + public BaseInStructure* Item1Ptr => (BaseInStructure*) (_headPtr + Item1Offset); /// /// Gets or sets item #1 in the chain. @@ -474,7 +654,7 @@ public unsafe class ManagedChain : ManagedChain /// /// Creates a new with 2 items from an existing memory block. /// - /// The pointer to the head of the chain.. + /// The pointer to the head of the chain. /// /// Callers are responsible for ensuring the size of the memory is correct. /// @@ -488,193 +668,365 @@ public unsafe class ManagedChain : ManagedChain /// /// The head of the chain. /// Item 1. - public ManagedChain(TChain head = default, T1 item1 = default) + internal ManagedChain(TChain head = default, T1 item1 = default) : this(Marshal.AllocHGlobal(MemorySize)) { head.StructureType(); Marshal.StructureToPtr(head, _headPtr, false); - Chain* itemPtr = Item1Ptr; + var itemPtr = Item1Ptr; item1.StructureType(); Marshal.StructureToPtr(item1, (nint)itemPtr, false); HeadPtr->PNext = itemPtr; Item1Ptr->PNext = null; } + /// + public override IEnumerator GetEnumerator() + { + yield return Head; + yield return Item1; + } + + /// + public override int Count => 2; + + /// + public override IChainable this[int index] + => index switch + { + 0 => Head, + 1 => Item1, + _ => throw new IndexOutOfRangeException() + }; + /// - /// Creates a new with 2 items from an existing unmanaged chain. + /// Compares the supplied memory block with this one, ignoring the structure headers. /// - /// Any errors loading the chain. - /// The unmanaged chain to use as the basis of this chain. - public ManagedChain(out string errors, TChain chain) - : this(Marshal.AllocHGlobal(MemorySize)) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override bool MemoryEquals(ManagedChain other) { - chain.StructureType(); - Marshal.StructureToPtr(chain, _headPtr, false); - StringBuilder errorBuilder = new StringBuilder(); - var existingPtr = (Chain*) Unsafe.AsPointer(ref chain); - var newPtr = (Chain*) _headPtr; + var ptr = HeadPtr; + var otherPtr = other.HeadPtr; + if (ptr == otherPtr) { + return true; + } + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var otherSpan = new ReadOnlySpan((void*) otherPtr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + if (sliceLength > 0 && + !span.Slice(start + HeaderSize, sliceLength) + .SequenceEqual(otherSpan.Slice(start + HeaderSize, sliceLength))) + return false; + return true; + } - existingPtr = existingPtr->PNext; - newPtr->PNext = (Chain*) (_headPtr + Item1Offset); - newPtr = newPtr->PNext; + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } - T1 item1 = default; - var expectedStructureType = item1.StructureType(); - if (existingPtr is null) { - errorBuilder.AppendLine("The unmanaged chain was length 1, expected length 2"); - } else { - if (existingPtr->SType != expectedStructureType) { - errorBuilder.Append("The unmanaged chain has a structure type ") - .Append(existingPtr->SType) - .Append(" at position 2; expected ") - .Append(expectedStructureType) - .AppendLine(); - } else { - if (existingPtr->PNext is not null) { - errorBuilder.AppendLine("The unmanaged chain was longer than the expected length 2"); - existingPtr->PNext = null; - } - item1 = Unsafe.AsRef(existingPtr); - } + + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(")"); + return sb.ToString(); + } + + /// + /// Deconstructs this chain. + /// + /// The head of the chain. + /// Item 1. + public void Deconstruct(out TChain head, out T1 item1) + { + head = Head; + item1 = Item1; + } + + /// + public override void Dispose() + { + var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); + if (headPtr == (nint)0) { + return; } - Marshal.StructureToPtr(item1, (nint) newPtr, false); - // Create string of errors - errors = errorBuilder.ToString().Trim(); + // Destroy all structures + Marshal.DestroyStructure(headPtr); + Marshal.DestroyStructure(headPtr + Item1Offset); + + // Free memory block + Marshal.FreeHGlobal(headPtr); } +} +``` + +## Extension methods +A static class is generated to hold the extension methods (showing one example set): +```csharp + +/// +/// Static class providing extension methods for manipulating managed chains. +/// +/// The `Any` versions of chain methods do not validate that items belong in the chain, this is +/// useful for situations where the specification does not indicate required chain constraints. You should generally +/// try to use the none `Any` version in preference. +public static unsafe class ManagedChainExtensions +{ + ... + /// - /// Creates a new with 2 by copying this chain. + /// Creates a new with 2 items, by appending to + /// the end of the . /// + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. /// - public ManagedChain Duplicate() - { - var newHeadPtr = Marshal.AllocHGlobal(MemorySize); - // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, MemorySize, MemorySize); - // Update all pointers - ((Chain*)newHeadPtr)->PNext = (Chain*) (newHeadPtr + Item1Offset); - return new ManagedChain(newHeadPtr); - } + /// + public static ManagedChain Add(this ManagedChain chain, T1 item1 = default) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + => chain.AddAny(item1); /// - /// Creates a new with 2 items, by appending - /// to the end of this chain. + /// Creates a new with 2 items, by appending to + /// the end of the . /// - /// The chain to append to. - /// Item 1. + /// The chain. + /// The item to append. + /// The chain type + /// Type of Item 1. /// - /// Do not forget to dispose the chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. /// - public ManagedChain(ManagedChain previous, T1 item1 = default) - : this(Marshal.AllocHGlobal(MemorySize)) + /// + public static ManagedChain AddAny(this ManagedChain chain, T1 item1 = default) + where TChain : struct, IChainable + where T1 : struct, IChainable { - var previousSize = MemorySize - Item1Size; + var previousSize = ManagedChain.MemorySize; + var newSize = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(newSize); // Block copy original struct data for speed - Buffer.MemoryCopy(previous.HeadPtr, (void*)_headPtr, previousSize, previousSize); + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, previousSize, previousSize); - // Append item 1 + // Append item 0 item1.StructureType(); - Marshal.StructureToPtr(item1, _headPtr + previousSize, false); + Marshal.StructureToPtr(item1, newHeadPtr + previousSize, false); // Update all pointers - ((Chain*)_headPtr)->PNext = (Chain*) (_headPtr + Item1Offset); - ((Chain*)(_headPtr + previousSize))->PNext = null; + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + ((BaseInStructure*)(newHeadPtr + previousSize))->PNext = null; + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 1 items, by removing the last item - /// from this chain. + /// Creates a new with 2 by copying the . /// + /// The chain. + /// The chain type + /// Type of Item 1. /// /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain Truncate() - { - return Truncate(out var _); - } - + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Duplicate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + => chain.DuplicateAny(); + /// - /// Creates a new with 1 items, by removing - /// from the end of this chain. + /// Creates a new with 2 by copying the . /// + /// The chain. + /// The chain type + /// Type of Item 1. /// - /// Do not forget to dispose this chain if you are no longer using it. + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. /// - public ManagedChain Truncate(out T1 item1) + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain DuplicateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable { - item1 = Item1; - - var newSize = MemorySize - Item1Size; - var newHeadPtr = Marshal.AllocHGlobal(newSize); + var size = ManagedChain.MemorySize; + var newHeadPtr = Marshal.AllocHGlobal(size); // Block copy original struct data for speed - Buffer.MemoryCopy((void*)_headPtr, (void*)newHeadPtr, newSize, newSize); + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, size, size); // Update all pointers - ((Chain*)newHeadPtr)->PNext = null; - return new ManagedChain(newHeadPtr); + ((BaseInStructure*)newHeadPtr)->PNext = (BaseInStructure*) (newHeadPtr + ManagedChain.Item1Offset); + return new ManagedChain(newHeadPtr); } /// - /// Creates a new with 3 items, by appending to - /// the end of this chain. + /// Creates a new with 1 items, by removing the last item + /// from the . /// - /// Item 2. - /// Type of Item 2 + /// The chain. + /// The chain type + /// Type of Item 1. /// /// Do not forget to dispose this chain if you are no longer using it. /// - public ManagedChain Append(T2 item2 = default) - where T2: struct, IExtendsChain - { - return new ManagedChain(this, item2); - } - - /// - public override IEnumerator GetEnumerator() - { - yield return Head; - yield return Item1; - } - - /// - public override int Count => 2; + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + => chain.TruncateAny(out var _); - /// - public override IChainable this[int index] - => index switch - { - 0 => Head, - 1 => Item1, - _ => throw new IndexOutOfRangeException() - }; + /// + /// Creates a new with 1 items, by removing the last item + /// from the . + /// + /// The chain. + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain TruncateAny(this ManagedChain chain) + where TChain : struct, IChainable + where T1 : struct, IChainable + => chain.TruncateAny(out var _); /// - /// Deconstructs this chain. + /// Creates a new with 1 items, by removing + /// from the end of the . /// - /// The head of the chain. - /// Item 1. - public void Deconstruct(out TChain head, out T1 item1) - { - head = Head; - item1 = Item1; - } + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ManagedChain Truncate(this ManagedChain chain, out T1 item1) + where TChain : struct, IChainStart + where T1 : struct, IExtendsChain + => chain.TruncateAny(out item1); - /// - public override void Dispose() + /// + /// Creates a new with 1 items, by removing + /// from the end of the . + /// + /// The chain. + /// The item removed from the . + /// The chain type + /// Type of Item 1. + /// + /// Do not forget to dispose this chain if you are no longer using it. + /// The `Any` versions of chain methods do not validate that items belong in the chain, this is + /// useful for situations where the specification does not indicate required chain constraints. You should generally + /// try to use the none `Any` version in preference. + /// + /// + /// + /// + public static ManagedChain TruncateAny(this ManagedChain chain, out T1 item1) + where TChain : struct, IChainable + where T1 : struct, IChainable { - var headPtr = Interlocked.Exchange(ref _headPtr, (nint)0); - if (headPtr == (nint)0) { - return; - } + // Retrieve last item. + item1 = chain.Item1; - // Destroy all structures - Marshal.DestroyStructure(headPtr); - Marshal.DestroyStructure(headPtr + Item1Offset); - - // Free memory block - Marshal.FreeHGlobal(headPtr); + var newSize = ManagedChain.MemorySize - ManagedChain.Item1Size; + var newHeadPtr = Marshal.AllocHGlobal(newSize); + // Block copy original struct data for speed + System.Buffer.MemoryCopy(chain.HeadPtr, (void*)newHeadPtr, newSize, newSize); + // Update all pointers + ((BaseInStructure*)newHeadPtr)->PNext = null; + return new ManagedChain(newHeadPtr); } + + ... } ``` \ No newline at end of file diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs index fe83c428cb..33a512a15a 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining.Test/TestManagedChains.cs @@ -393,4 +393,61 @@ public void TestDeconstructor() Assert.Equal (StructureType.PhysicalDeviceAccelerationStructureFeaturesKhr, accelerationStructureFeaturesKhr.SType); } + + [Fact] + public unsafe void TestManagedChainGetHashCode() + { + using var chain = ManagedChain.Create + ( + item1: new PhysicalDeviceDescriptorIndexingFeatures {ShaderInputAttachmentArrayDynamicIndexing = true} + ); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal(0, (nint) chain.Item1.PNext); + + // Check flag set + Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + using var newChain = chain.Duplicate(); + + // Ensure all STypes set correctly + Assert.Equal(StructureType.PhysicalDeviceFeatures2, chain.Head.SType); + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1.SType); + + Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1Ptr->SType); + + // Ensure pointers set correctly + Assert.Equal((nint) chain.Item1Ptr, (nint) chain.Head.PNext); + Assert.Equal(0, (nint) chain.Item1.PNext); + + // Check flag set + Assert.True(chain.Item1.ShaderInputAttachmentArrayDynamicIndexing); + + // Check we have new copies + Assert.NotEqual((nint) chain.HeadPtr, (nint) newChain.HeadPtr); + Assert.NotEqual((nint) chain.Item1Ptr, (nint) newChain.Item1Ptr); + + // Test equality + Assert.Equal(chain, newChain); + Assert.True(chain == newChain); + var hashCode = chain.GetHashCode(); + var newHashCode = newChain.GetHashCode(); + Assert.Equal(hashCode, newHashCode); + + // Modify second chain + newChain.Item1 = default; + + // Test equality + Assert.NotEqual(chain, newChain); + Assert.False(chain == newChain); + Assert.Equal(hashCode, chain.GetHashCode()); + var newHashCode2 = newChain.GetHashCode(); + Assert.NotEqual(hashCode, newHashCode2); + Assert.NotEqual(newHashCode, newHashCode2); + } } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs index 03bf0e16ae..1680728d74 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/IChainable.cs @@ -8,5 +8,8 @@ namespace Silk.NET.Vulkan; /// to a pointer to a . public interface IChainable : IStructuredType { + /// + /// Points to the next in this chain, if any; otherwise . + /// unsafe BaseInStructure* PNext { get; set; } } diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs index c46b5f41b6..2c000b5c64 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs @@ -51,6 +51,21 @@ public override bool Equals(object obj) /// public abstract void Dispose(); + /// + /// Combines a hashcode with the first part of a slice. + /// + /// + /// + /// + protected static void CombineHash(ref int hashCode, ReadOnlySpan slice) => + hashCode = slice.Length switch + { + < 2 => HashCode.Combine(hashCode, slice[0]), + < 4 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), + < 8 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), + _ => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]) + }; + /// /// Creates a new with 1 items. /// @@ -10347,6 +10362,29 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -10558,6 +10596,37 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -10822,6 +10891,45 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -11139,6 +11247,53 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -11509,6 +11664,61 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -11932,6 +12142,69 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -12408,6 +12681,77 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -12937,6 +13281,85 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -13519,47 +13942,134 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(ManagedChain other) - => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(ManagedChain left, ManagedChain right) => - ReferenceEquals(null, left) - ? ReferenceEquals(null, right) - : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(ManagedChain left, ManagedChain right) => - ReferenceEquals(null, left) - ? !ReferenceEquals(null, right) - : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); - /// - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - sb.Append("("); - sb.Append((object) Head); sb.Append(", "); - sb.Append((object) Item1); - sb.Append(", "); - sb.Append((object) Item2); - sb.Append(", "); - sb.Append((object) Item3); - sb.Append(", "); - sb.Append((object) Item4); - sb.Append(", "); - sb.Append((object) Item5); - sb.Append(", "); - sb.Append((object) Item6); - sb.Append(", "); - sb.Append((object) Item7); - sb.Append(", "); - sb.Append((object) Item8); + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(ManagedChain other) + => !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || MemoryEquals(other)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? ReferenceEquals(null, right) + : !ReferenceEquals(null, right) && (ReferenceEquals(left, right) || left.MemoryEquals(right)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(ManagedChain left, ManagedChain right) => + ReferenceEquals(null, left) + ? !ReferenceEquals(null, right) + : ReferenceEquals(null, right) || (!ReferenceEquals(left, right) && !left.MemoryEquals(right)); + + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("("); + sb.Append((object) Head); sb.Append(", "); + sb.Append((object) Item1); + sb.Append(", "); + sb.Append((object) Item2); + sb.Append(", "); + sb.Append((object) Item3); + sb.Append(", "); + sb.Append((object) Item4); + sb.Append(", "); + sb.Append((object) Item5); + sb.Append(", "); + sb.Append((object) Item6); + sb.Append(", "); + sb.Append((object) Item7); + sb.Append(", "); + sb.Append((object) Item8); sb.Append(")"); return sb.ToString(); } @@ -14154,6 +14664,101 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -14842,6 +15447,109 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -15583,6 +16291,117 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -16377,6 +17196,125 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item12Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -17224,6 +18162,133 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item12Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item13Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -18124,6 +19189,141 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item12Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item13Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item14Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -19077,6 +20277,149 @@ protected override bool MemoryEquals(ManagedChain other) return false; return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item1Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item2Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item3Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item4Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item5Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item6Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item7Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item8Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item9Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item10Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item11Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item12Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item13Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item14Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + + start += length; + length = Item15Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt index 9e6777b740..b973d45cf8 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt @@ -163,6 +163,21 @@ public abstract unsafe class ManagedChain : IReadOnlyList, IDisposab /// public abstract void Dispose(); + /// + /// Combines a hashcode with the first part of a slice. + /// + /// + /// + /// + protected static void CombineHash(ref int hashCode, ReadOnlySpan slice) => + hashCode = slice.Length switch + { + < 2 => HashCode.Combine(hashCode, slice[0]), + < 4 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), + < 8 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), + _ => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]) + }; + <# for (var i = 1; i <= maximumItems; i++) { @@ -782,6 +797,44 @@ public unsafe sealed class ManagedChain<<#= tList #>> : ManagedChain, IEquatable #> return true; } + + /// + /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each + /// structure's 'payload'. + public override int GetHashCode() + { + var ptr = HeadPtr; + var span = new ReadOnlySpan((void*) ptr, MemorySize); + var start = 0; + var length = HeadSize; + var sliceLength = length - HeaderSize; + var hashCode = 0; + // Hash the structure type + var sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + + // Hash any payload + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); +<# + for (var j = 1; j < i; j++) + { +#> + + start += length; + length = Item<#=j#>Size; + sliceLength = length - HeaderSize; + sTYpe = (ptr + start)->SType; + hashCode = HashCode.Combine(hashCode, sTYpe); + if (sliceLength >= 0) + CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); +<# + } // for (int j = 1; j < i; j++) { +#> + return hashCode; + } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] From 930a2fc2690c39a06b862afb0484e6489fb87874 Mon Sep 17 00:00:00 2001 From: Craig Dean Date: Mon, 15 Nov 2021 13:45:32 +0000 Subject: [PATCH 34/34] fix: Fixed GetHashCode Fixed broken pointer arithmetic. Also changed to hash entire structure for better separation. --- ...n Struct Chaining - #3 Managed Chaining.md | 21 +- .../ManagedChain.gen.cs | 426 ++++++++---------- .../ManagedChain.gen.tt | 53 ++- 3 files changed, 231 insertions(+), 269 deletions(-) diff --git a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md index abb1f84939..d055b133ee 100644 --- a/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md +++ b/documentation/proposals/Proposal - Vulkan Struct Chaining - #3 Managed Chaining.md @@ -49,7 +49,7 @@ errors. Structures can be replaced at any time, and will be inserted efficiently safety. - The managed chains implement `IEquatable`, allowing two chains with identical content to be efficiently compared ( ignoring the `PNext` pointers, but already being confident the `SType` and ordering is correct). They also implement - the equality operator overloads, and `GetHashCode`. + the equality operator overloads, and `GetHashCode`. Open questions: @@ -66,9 +66,8 @@ Open questions: found in the unmanaged chain, no matter at what position they are found. This is not entirely unreasonable as the order of chains (after the start) is not fixed in Vulkan, and it will allow importing existing chains where the order doesn't matter. -- `GetHasCode` only includes the `SType` and, at most, the first 8 bytes of the payload, for speed. This is because a - HashCode only needs to generate reasonable separation, but does not need to be unique. It is possible, to hash the - entire memory block if desired, though at slightly worse performance. +- `GetHasCode` current hashes the entire struct's data, except the `PNext` fields. However, a hashcode only needs to + create reasonable separation so a 'sampling' method could be used for increased performance. - Similar to `Append` and `Truncate` we could also add `Insert` and `Remove` methods, though slightly more complex, as we'd have to generate multiples of each, it is not difficult to do, for example: @@ -339,7 +338,7 @@ Assert.IsType(structures[2]); ### Equality (IEquatable<T>) ll the fully generic `ManageChain` types implement the corresponding `IEquatable>` -interface, and equality operators. As well as `GetHashCode`. +interface, and equality operators. As well as `GetHashCode`. ### Deconstruction @@ -731,18 +730,15 @@ public unsafe sealed class ManagedChain : ManagedChain, IEquatable - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -752,14 +748,12 @@ public unsafe sealed class ManagedChain : ManagedChain, IEquatableSType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -823,6 +817,7 @@ public unsafe sealed class ManagedChain : ManagedChain, IEquatable diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs index 2c000b5c64..f7dc2b43b7 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.cs @@ -52,19 +52,45 @@ public override bool Equals(object obj) public abstract void Dispose(); /// - /// Combines a hashcode with the first part of a slice. + /// Combines a hashcode with the contents of a slice. /// /// /// /// - protected static void CombineHash(ref int hashCode, ReadOnlySpan slice) => - hashCode = slice.Length switch + protected static void CombineHash(ref int hashCode, ReadOnlySpan slice) + { + if (slice.Length >= 8) { - < 2 => HashCode.Combine(hashCode, slice[0]), - < 4 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), - < 8 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), - _ => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]) - }; + // Process slice in 8 byte chunks + var s8 = MemoryMarshal.Cast(slice); + foreach (var l in s8) + { + hashCode = HashCode.Combine(hashCode, l); + } + + slice = slice.Slice(s8.Length*8); + } + + // Process remainder of slice + if (slice.Length >= 4) + { + var s4 = MemoryMarshal.Cast(slice); + hashCode = HashCode.Combine(hashCode, s4[0]); + slice = slice.Slice(s4.Length*4); + } + + if (slice.Length >= 2) + { + var s2 = MemoryMarshal.Cast(slice); + hashCode = HashCode.Combine(hashCode, s2[0]); + slice = slice.Slice(s2.Length*2); + } + + if (slice.Length > 0) + { + hashCode = HashCode.Combine(hashCode, slice[0]); + } + } /// /// Creates a new with 1 items. @@ -10364,18 +10390,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -10384,8 +10407,6 @@ public override int GetHashCode() return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -10598,18 +10619,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -10619,15 +10637,13 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -10893,18 +10909,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -10914,7 +10927,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -10922,15 +10935,13 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -11249,18 +11260,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -11270,7 +11278,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -11278,7 +11286,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -11286,15 +11294,13 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -11666,18 +11672,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -11687,7 +11690,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -11695,7 +11698,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -11703,7 +11706,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -11711,15 +11714,13 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -12144,18 +12145,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -12165,7 +12163,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -12173,7 +12171,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -12181,7 +12179,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -12189,7 +12187,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -12197,15 +12195,13 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -12683,18 +12679,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -12704,7 +12697,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -12712,7 +12705,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -12720,7 +12713,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -12728,7 +12721,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -12736,7 +12729,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -12744,15 +12737,13 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -13283,18 +13274,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -13304,7 +13292,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13312,7 +13300,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13320,7 +13308,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13328,7 +13316,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13336,7 +13324,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13344,7 +13332,7 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13352,15 +13340,13 @@ public override int GetHashCode() start += length; length = Item7Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -13944,18 +13930,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -13965,7 +13948,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13973,7 +13956,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13981,7 +13964,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13989,7 +13972,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -13997,7 +13980,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14005,7 +13988,7 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14013,7 +13996,7 @@ public override int GetHashCode() start += length; length = Item7Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14021,15 +14004,13 @@ public override int GetHashCode() start += length; length = Item8Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -14666,18 +14647,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -14687,7 +14665,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14695,7 +14673,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14703,7 +14681,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14711,7 +14689,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14719,7 +14697,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14727,7 +14705,7 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14735,7 +14713,7 @@ public override int GetHashCode() start += length; length = Item7Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14743,7 +14721,7 @@ public override int GetHashCode() start += length; length = Item8Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -14751,15 +14729,13 @@ public override int GetHashCode() start += length; length = Item9Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -15449,18 +15425,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -15470,7 +15443,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -15478,7 +15451,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -15486,7 +15459,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -15494,7 +15467,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -15502,7 +15475,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -15510,7 +15483,7 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -15518,7 +15491,7 @@ public override int GetHashCode() start += length; length = Item7Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -15526,7 +15499,7 @@ public override int GetHashCode() start += length; length = Item8Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -15534,7 +15507,7 @@ public override int GetHashCode() start += length; length = Item9Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -15542,15 +15515,13 @@ public override int GetHashCode() start += length; length = Item10Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -16293,18 +16264,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -16314,7 +16282,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16322,7 +16290,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16330,7 +16298,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16338,7 +16306,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16346,7 +16314,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16354,7 +16322,7 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16362,7 +16330,7 @@ public override int GetHashCode() start += length; length = Item7Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16370,7 +16338,7 @@ public override int GetHashCode() start += length; length = Item8Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16378,7 +16346,7 @@ public override int GetHashCode() start += length; length = Item9Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16386,7 +16354,7 @@ public override int GetHashCode() start += length; length = Item10Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -16394,15 +16362,13 @@ public override int GetHashCode() start += length; length = Item11Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -17198,18 +17164,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -17219,7 +17182,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17227,7 +17190,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17235,7 +17198,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17243,7 +17206,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17251,7 +17214,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17259,7 +17222,7 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17267,7 +17230,7 @@ public override int GetHashCode() start += length; length = Item7Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17275,7 +17238,7 @@ public override int GetHashCode() start += length; length = Item8Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17283,7 +17246,7 @@ public override int GetHashCode() start += length; length = Item9Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17291,7 +17254,7 @@ public override int GetHashCode() start += length; length = Item10Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17299,7 +17262,7 @@ public override int GetHashCode() start += length; length = Item11Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -17307,15 +17270,13 @@ public override int GetHashCode() start += length; length = Item12Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -18164,18 +18125,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -18185,7 +18143,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18193,7 +18151,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18201,7 +18159,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18209,7 +18167,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18217,7 +18175,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18225,7 +18183,7 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18233,7 +18191,7 @@ public override int GetHashCode() start += length; length = Item7Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18241,7 +18199,7 @@ public override int GetHashCode() start += length; length = Item8Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18249,7 +18207,7 @@ public override int GetHashCode() start += length; length = Item9Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18257,7 +18215,7 @@ public override int GetHashCode() start += length; length = Item10Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18265,7 +18223,7 @@ public override int GetHashCode() start += length; length = Item11Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18273,7 +18231,7 @@ public override int GetHashCode() start += length; length = Item12Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -18281,15 +18239,13 @@ public override int GetHashCode() start += length; length = Item13Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -19191,18 +19147,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -19212,7 +19165,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19220,7 +19173,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19228,7 +19181,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19236,7 +19189,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19244,7 +19197,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19252,7 +19205,7 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19260,7 +19213,7 @@ public override int GetHashCode() start += length; length = Item7Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19268,7 +19221,7 @@ public override int GetHashCode() start += length; length = Item8Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19276,7 +19229,7 @@ public override int GetHashCode() start += length; length = Item9Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19284,7 +19237,7 @@ public override int GetHashCode() start += length; length = Item10Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19292,7 +19245,7 @@ public override int GetHashCode() start += length; length = Item11Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19300,7 +19253,7 @@ public override int GetHashCode() start += length; length = Item12Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19308,7 +19261,7 @@ public override int GetHashCode() start += length; length = Item13Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -19316,15 +19269,13 @@ public override int GetHashCode() start += length; length = Item14Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) @@ -20279,18 +20230,15 @@ protected override bool MemoryEquals(ManagedChain other) } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -20300,7 +20248,7 @@ public override int GetHashCode() start += length; length = Item1Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20308,7 +20256,7 @@ public override int GetHashCode() start += length; length = Item2Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20316,7 +20264,7 @@ public override int GetHashCode() start += length; length = Item3Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20324,7 +20272,7 @@ public override int GetHashCode() start += length; length = Item4Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20332,7 +20280,7 @@ public override int GetHashCode() start += length; length = Item5Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20340,7 +20288,7 @@ public override int GetHashCode() start += length; length = Item6Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20348,7 +20296,7 @@ public override int GetHashCode() start += length; length = Item7Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20356,7 +20304,7 @@ public override int GetHashCode() start += length; length = Item8Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20364,7 +20312,7 @@ public override int GetHashCode() start += length; length = Item9Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20372,7 +20320,7 @@ public override int GetHashCode() start += length; length = Item10Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20380,7 +20328,7 @@ public override int GetHashCode() start += length; length = Item11Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20388,7 +20336,7 @@ public override int GetHashCode() start += length; length = Item12Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20396,7 +20344,7 @@ public override int GetHashCode() start += length; length = Item13Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20404,7 +20352,7 @@ public override int GetHashCode() start += length; length = Item14Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -20412,15 +20360,13 @@ public override int GetHashCode() start += length; length = Item15Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain other) diff --git a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt index b973d45cf8..2b24298029 100644 --- a/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt +++ b/src/Lab/Experiments/PrototypeStructChaining/PrototypeStructChaining/ManagedChain.gen.tt @@ -164,19 +164,45 @@ public abstract unsafe class ManagedChain : IReadOnlyList, IDisposab public abstract void Dispose(); /// - /// Combines a hashcode with the first part of a slice. + /// Combines a hashcode with the contents of a slice. /// /// /// /// - protected static void CombineHash(ref int hashCode, ReadOnlySpan slice) => - hashCode = slice.Length switch + protected static void CombineHash(ref int hashCode, ReadOnlySpan slice) + { + if (slice.Length >= 8) { - < 2 => HashCode.Combine(hashCode, slice[0]), - < 4 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), - < 8 => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]), - _ => HashCode.Combine(hashCode, MemoryMarshal.Cast(slice)[0]) - }; + // Process slice in 8 byte chunks + var s8 = MemoryMarshal.Cast(slice); + foreach (var l in s8) + { + hashCode = HashCode.Combine(hashCode, l); + } + + slice = slice.Slice(s8.Length*8); + } + + // Process remainder of slice + if (slice.Length >= 4) + { + var s4 = MemoryMarshal.Cast(slice); + hashCode = HashCode.Combine(hashCode, s4[0]); + slice = slice.Slice(s4.Length*4); + } + + if (slice.Length >= 2) + { + var s2 = MemoryMarshal.Cast(slice); + hashCode = HashCode.Combine(hashCode, s2[0]); + slice = slice.Slice(s2.Length*2); + } + + if (slice.Length > 0) + { + hashCode = HashCode.Combine(hashCode, slice[0]); + } + } <# for (var i = 1; i <= maximumItems; i++) @@ -799,18 +825,15 @@ public unsafe sealed class ManagedChain<<#= tList #>> : ManagedChain, IEquatable } /// - /// HashCodes do not need to be unique, so ww only sample the structure type and the start of each - /// structure's 'payload'. public override int GetHashCode() { - var ptr = HeadPtr; - var span = new ReadOnlySpan((void*) ptr, MemorySize); + var span = new ReadOnlySpan((void*)_headPtr, MemorySize); var start = 0; var length = HeadSize; var sliceLength = length - HeaderSize; var hashCode = 0; // Hash the structure type - var sTYpe = (ptr + start)->SType; + var sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); // Hash any payload @@ -824,7 +847,7 @@ public unsafe sealed class ManagedChain<<#= tList #>> : ManagedChain, IEquatable start += length; length = Item<#=j#>Size; sliceLength = length - HeaderSize; - sTYpe = (ptr + start)->SType; + sTYpe = ((BaseInStructure*) (_headPtr + start))->SType; hashCode = HashCode.Combine(hashCode, sTYpe); if (sliceLength >= 0) CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength)); @@ -834,8 +857,6 @@ public unsafe sealed class ManagedChain<<#= tList #>> : ManagedChain, IEquatable return hashCode; } - - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ManagedChain<<#=tList#>> other)