├── .gitignore ├── Benchmark ├── App.config ├── Benchmark.csproj ├── DictionaryBench.cs ├── ListAddBench.cs ├── ListAddExpand.cs ├── ListIndexOf.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── QueueBench.cs ├── SortedSetBench.cs └── packages.config ├── LICENSE ├── README.md ├── UnsafeCollections.sln ├── UnsafeCollections ├── AssemblyInfo.cs ├── Collections │ ├── Native │ │ ├── Concurrent │ │ │ ├── NativeMPMCQueue.cs │ │ │ ├── NativeMPSCQueue.cs │ │ │ └── NativeSPSCQueue.cs │ │ ├── INativeArray.cs │ │ ├── INativeCollection.cs │ │ ├── INativeDictionary.cs │ │ ├── INativeReadOnlyCollection.cs │ │ ├── NativeArray.cs │ │ ├── NativeBitSet.cs │ │ ├── NativeDictionary.cs │ │ ├── NativeHashSet.cs │ │ ├── NativeLinkedList.cs │ │ ├── NativeList.cs │ │ ├── NativeQueue.cs │ │ ├── NativeRingBuffer.cs │ │ ├── NativeSortedDictionary.cs │ │ ├── NativeSortedSet.cs │ │ └── NativeStack.cs │ └── Unsafe │ │ ├── Concurrent │ │ ├── HeadAndTail.cs │ │ ├── QueueSegment.cs │ │ ├── UnsafeMPMCQueue.cs │ │ ├── UnsafeMPSCQueue.cs │ │ └── UnsafeSPSCQueue.cs │ │ ├── IUnsafeIterator.cs │ │ ├── MapInsertionBehaviour.cs │ │ ├── UnsafeArray.cs │ │ ├── UnsafeBitSet.cs │ │ ├── UnsafeBuffer.cs │ │ ├── UnsafeDictionary.cs │ │ ├── UnsafeHashCollection.cs │ │ ├── UnsafeHashSet.cs │ │ ├── UnsafeHeapMinMax.cs │ │ ├── UnsafeLinkedList.cs │ │ ├── UnsafeList.cs │ │ ├── UnsafeLock.cs │ │ ├── UnsafeOrderedCollection.cs │ │ ├── UnsafeQueue.cs │ │ ├── UnsafeRingBuffer.cs │ │ ├── UnsafeSortedDictionary.cs │ │ ├── UnsafeSortedSet.cs │ │ └── UnsafeStack.cs ├── Debug │ ├── AssertException.cs │ ├── ThrowHelper.cs │ ├── TypeProxies │ │ ├── NativeArrayDebugView.cs │ │ ├── NativeBitSetDebugView.cs │ │ ├── NativeCollectionDebugView.cs │ │ ├── NativeDictionaryDebugView.cs │ │ └── NativeReadOnlyCollectionDebugView.cs │ └── UDebug.cs ├── Memory.cs └── UnsafeCollections.csproj └── UnsafeCollectionsTests ├── Native ├── NativeArrayTests.cs ├── NativeListTests.cs └── NativeSortedDictionaryTests.cs ├── Unsafe ├── Concurrent │ ├── UnsafeMPMCQueueTests.cs │ ├── UnsafeMPSCQueueTests.cs │ └── UnsafeSPSCQueueTests.cs ├── UnsafeArrayTests.cs ├── UnsafeBitSetTests.cs ├── UnsafeHashMapTests.cs ├── UnsafeHashSetTests.cs ├── UnsafeHeapTests.cs ├── UnsafeLinkedListTests.cs ├── UnsafeListTest.cs ├── UnsafeLockTest.cs ├── UnsafeOrderedDictionaryTests.cs ├── UnsafeOrderedSetTests.cs ├── UnsafeQueueTests.cs ├── UnsafeRingBufferTests.cs └── UnsafeStackTests.cs └── UnsafeCollectionsTests.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudio 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio 3 | 4 | ### VisualStudio ### 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | ## 8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 9 | 10 | # User-specific files 11 | *.rsuser 12 | *.suo 13 | *.user 14 | *.userosscache 15 | *.sln.docstates 16 | 17 | # User-specific files (MonoDevelop/Xamarin Studio) 18 | *.userprefs 19 | 20 | # Mono auto generated files 21 | mono_crash.* 22 | 23 | # Build results 24 | [Dd]ebugPublic/ 25 | [Rr]elease/ 26 | [Rr]eleases/ 27 | x64/ 28 | x86/ 29 | [Aa][Rr][Mm]/ 30 | [Aa][Rr][Mm]64/ 31 | bld/ 32 | [Bb]in/ 33 | [Oo]bj/ 34 | [Ll]og/ 35 | [Ll]ogs/ 36 | 37 | # Visual Studio 2015/2017 cache/options directory 38 | .vs/ 39 | # Uncomment if you have tasks that create the project's static files in wwwroot 40 | #wwwroot/ 41 | 42 | # Visual Studio 2017 auto generated files 43 | Generated\ Files/ 44 | 45 | # MSTest test Results 46 | [Tt]est[Rr]esult*/ 47 | [Bb]uild[Ll]og.* 48 | 49 | # NUnit 50 | *.VisualState.xml 51 | TestResult.xml 52 | nunit-*.xml 53 | 54 | # Build Results of an ATL Project 55 | [Dd]ebugPS/ 56 | [Rr]eleasePS/ 57 | dlldata.c 58 | 59 | # Benchmark Results 60 | BenchmarkDotNet.Artifacts/ 61 | 62 | # .NET Core 63 | project.lock.json 64 | project.fragment.lock.json 65 | artifacts/ 66 | 67 | # StyleCop 68 | StyleCopReport.xml 69 | 70 | # Files built by Visual Studio 71 | *_i.c 72 | *_p.c 73 | *_h.h 74 | *.ilk 75 | *.meta 76 | *.obj 77 | *.iobj 78 | *.pch 79 | *.pdb 80 | *.ipdb 81 | *.pgc 82 | *.pgd 83 | *.rsp 84 | *.sbr 85 | *.tlb 86 | *.tli 87 | *.tlh 88 | *.tmp 89 | *.tmp_proj 90 | *_wpftmp.csproj 91 | *.log 92 | *.vspscc 93 | *.vssscc 94 | .builds 95 | *.pidb 96 | *.svclog 97 | *.scc 98 | 99 | # Chutzpah Test files 100 | _Chutzpah* 101 | 102 | # Visual C++ cache files 103 | ipch/ 104 | *.aps 105 | *.ncb 106 | *.opendb 107 | *.opensdf 108 | *.sdf 109 | *.cachefile 110 | *.VC.db 111 | *.VC.VC.opendb 112 | 113 | # Visual Studio profiler 114 | *.psess 115 | *.vsp 116 | *.vspx 117 | *.sap 118 | 119 | # Visual Studio Trace Files 120 | *.e2e 121 | 122 | # TFS 2012 Local Workspace 123 | $tf/ 124 | 125 | # Guidance Automation Toolkit 126 | *.gpState 127 | 128 | # ReSharper is a .NET coding add-in 129 | _ReSharper*/ 130 | *.[Rr]e[Ss]harper 131 | *.DotSettings.user 132 | 133 | # TeamCity is a build add-in 134 | _TeamCity* 135 | 136 | # DotCover is a Code Coverage Tool 137 | *.dotCover 138 | 139 | # AxoCover is a Code Coverage Tool 140 | .axoCover/* 141 | !.axoCover/settings.json 142 | 143 | # Coverlet is a free, cross platform Code Coverage Tool 144 | coverage*[.json, .xml, .info] 145 | 146 | # Visual Studio code coverage results 147 | *.coverage 148 | *.coveragexml 149 | 150 | # NCrunch 151 | _NCrunch_* 152 | .*crunch*.local.xml 153 | nCrunchTemp_* 154 | 155 | # MightyMoose 156 | *.mm.* 157 | AutoTest.Net/ 158 | 159 | # Web workbench (sass) 160 | .sass-cache/ 161 | 162 | # Installshield output folder 163 | [Ee]xpress/ 164 | 165 | # DocProject is a documentation generator add-in 166 | DocProject/buildhelp/ 167 | DocProject/Help/*.HxT 168 | DocProject/Help/*.HxC 169 | DocProject/Help/*.hhc 170 | DocProject/Help/*.hhk 171 | DocProject/Help/*.hhp 172 | DocProject/Help/Html2 173 | DocProject/Help/html 174 | 175 | # Click-Once directory 176 | publish/ 177 | 178 | # Publish Web Output 179 | *.[Pp]ublish.xml 180 | *.azurePubxml 181 | # Note: Comment the next line if you want to checkin your web deploy settings, 182 | # but database connection strings (with potential passwords) will be unencrypted 183 | *.pubxml 184 | *.publishproj 185 | 186 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 187 | # checkin your Azure Web App publish settings, but sensitive information contained 188 | # in these scripts will be unencrypted 189 | PublishScripts/ 190 | 191 | # NuGet Packages 192 | *.nupkg 193 | # NuGet Symbol Packages 194 | *.snupkg 195 | # The packages folder can be ignored because of Package Restore 196 | **/[Pp]ackages/* 197 | # except build/, which is used as an MSBuild target. 198 | !**/[Pp]ackages/build/ 199 | # Uncomment if necessary however generally it will be regenerated when needed 200 | #!**/[Pp]ackages/repositories.config 201 | # NuGet v3's project.json files produces more ignorable files 202 | *.nuget.props 203 | *.nuget.targets 204 | 205 | # Microsoft Azure Build Output 206 | csx/ 207 | *.build.csdef 208 | 209 | # Microsoft Azure Emulator 210 | ecf/ 211 | rcf/ 212 | 213 | # Windows Store app package directories and files 214 | AppPackages/ 215 | BundleArtifacts/ 216 | Package.StoreAssociation.xml 217 | _pkginfo.txt 218 | *.appx 219 | *.appxbundle 220 | *.appxupload 221 | 222 | # Visual Studio cache files 223 | # files ending in .cache can be ignored 224 | *.[Cc]ache 225 | # but keep track of directories ending in .cache 226 | !?*.[Cc]ache/ 227 | 228 | # Others 229 | ClientBin/ 230 | ~$* 231 | *~ 232 | *.dbmdl 233 | *.dbproj.schemaview 234 | *.jfm 235 | *.pfx 236 | *.publishsettings 237 | orleans.codegen.cs 238 | 239 | # Including strong name files can present a security risk 240 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 241 | #*.snk 242 | 243 | # Since there are multiple workflows, uncomment next line to ignore bower_components 244 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 245 | #bower_components/ 246 | 247 | # RIA/Silverlight projects 248 | Generated_Code/ 249 | 250 | # Backup & report files from converting an old project file 251 | # to a newer Visual Studio version. Backup files are not needed, 252 | # because we have git ;-) 253 | _UpgradeReport_Files/ 254 | Backup*/ 255 | UpgradeLog*.XML 256 | UpgradeLog*.htm 257 | ServiceFabricBackup/ 258 | *.rptproj.bak 259 | 260 | # SQL Server files 261 | *.mdf 262 | *.ldf 263 | *.ndf 264 | 265 | # Business Intelligence projects 266 | *.rdl.data 267 | *.bim.layout 268 | *.bim_*.settings 269 | *.rptproj.rsuser 270 | *- [Bb]ackup.rdl 271 | *- [Bb]ackup ([0-9]).rdl 272 | *- [Bb]ackup ([0-9][0-9]).rdl 273 | 274 | # Microsoft Fakes 275 | FakesAssemblies/ 276 | 277 | # GhostDoc plugin setting file 278 | *.GhostDoc.xml 279 | 280 | # Node.js Tools for Visual Studio 281 | .ntvs_analysis.dat 282 | node_modules/ 283 | 284 | # Visual Studio 6 build log 285 | *.plg 286 | 287 | # Visual Studio 6 workspace options file 288 | *.opt 289 | 290 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 291 | *.vbw 292 | 293 | # Visual Studio LightSwitch build output 294 | **/*.HTMLClient/GeneratedArtifacts 295 | **/*.DesktopClient/GeneratedArtifacts 296 | **/*.DesktopClient/ModelManifest.xml 297 | **/*.Server/GeneratedArtifacts 298 | **/*.Server/ModelManifest.xml 299 | _Pvt_Extensions 300 | 301 | # Paket dependency manager 302 | .paket/paket.exe 303 | paket-files/ 304 | 305 | # FAKE - F# Make 306 | .fake/ 307 | 308 | # CodeRush personal settings 309 | .cr/personal 310 | 311 | # Python Tools for Visual Studio (PTVS) 312 | __pycache__/ 313 | *.pyc 314 | 315 | # Cake - Uncomment if you are using it 316 | # tools/** 317 | # !tools/packages.config 318 | 319 | # Tabs Studio 320 | *.tss 321 | 322 | # Telerik's JustMock configuration file 323 | *.jmconfig 324 | 325 | # BizTalk build output 326 | *.btp.cs 327 | *.btm.cs 328 | *.odx.cs 329 | *.xsd.cs 330 | 331 | # OpenCover UI analysis results 332 | OpenCover/ 333 | 334 | # Azure Stream Analytics local run output 335 | ASALocalRun/ 336 | 337 | # MSBuild Binary and Structured Log 338 | *.binlog 339 | 340 | # NVidia Nsight GPU debugger configuration file 341 | *.nvuser 342 | 343 | # MFractors (Xamarin productivity tool) working folder 344 | .mfractor/ 345 | 346 | # Local History for Visual Studio 347 | .localhistory/ 348 | 349 | # BeatPulse healthcheck temp database 350 | healthchecksdb 351 | 352 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 353 | MigrationBackup/ 354 | 355 | # Ionide (cross platform F# VS Code tools) working folder 356 | .ionide/ 357 | 358 | # End of https://www.toptal.com/developers/gitignore/api/visualstudio -------------------------------------------------------------------------------- /Benchmark/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Benchmark/DictionaryBench.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnsafeCollections.Collections.Native; 8 | 9 | namespace Benchmark 10 | { 11 | public class DictionaryBench 12 | { 13 | const int COUNT = 32; 14 | 15 | NativeDictionary ndict = new NativeDictionary(COUNT); 16 | Dictionary dict = new Dictionary(COUNT); 17 | 18 | public DictionaryBench() 19 | { 20 | 21 | } 22 | 23 | ~DictionaryBench() 24 | { 25 | ndict.Dispose(); 26 | } 27 | 28 | [Benchmark] 29 | public void SortedSetAdd() 30 | { 31 | for (int i = 0; i < COUNT; i++) 32 | { 33 | dict.Add(i, i * i); 34 | } 35 | 36 | for (int i = 0; i < COUNT; i++) 37 | { 38 | dict.Remove(i); 39 | } 40 | } 41 | 42 | [Benchmark] 43 | public void NativeSortedSetAdd() 44 | { 45 | for (int i = 0; i < COUNT; i++) 46 | { 47 | ndict.Add(i, i * i); 48 | } 49 | 50 | for (int i = 0; i < COUNT; i++) 51 | { 52 | ndict.Remove(i); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/ListAddBench.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnsafeCollections.Collections.Native; 8 | using UnsafeCollections.Collections.Unsafe; 9 | 10 | namespace Benchmark 11 | { 12 | [MemoryDiagnoser] 13 | public unsafe class ListAddBench 14 | { 15 | const int COUNT = 32; 16 | NativeList nList = new NativeList(COUNT); 17 | List list = new List(COUNT); 18 | UnsafeList* uList = UnsafeList.Allocate(COUNT); 19 | 20 | ~ListAddBench() 21 | { 22 | nList.Dispose(); 23 | UnsafeList.Free(uList); 24 | } 25 | 26 | [Benchmark] 27 | public void ListAdd() 28 | { 29 | for (int i = 0; i < COUNT; i++) 30 | { 31 | list.Add(i); 32 | } 33 | 34 | list.Clear(); 35 | } 36 | 37 | [Benchmark] 38 | public void NativeListAdd() 39 | { 40 | for (int i = 0; i < COUNT; i++) 41 | { 42 | nList.Add(i); 43 | } 44 | 45 | nList.Clear(); 46 | } 47 | 48 | [Benchmark] 49 | public void UnsafeListAdd() 50 | { 51 | for (int i = 0; i < COUNT; i++) 52 | { 53 | UnsafeList.Add(uList, i); 54 | } 55 | 56 | UnsafeList.Clear(uList); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Benchmark/ListAddExpand.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnsafeCollections.Collections.Native; 8 | using UnsafeCollections.Collections.Unsafe; 9 | 10 | namespace Benchmark 11 | { 12 | [MemoryDiagnoser] 13 | public unsafe class ListAddExpand 14 | { 15 | const int COUNT = 8; 16 | const int COUNTMAX = 65; 17 | 18 | NativeList nList = new NativeList(COUNT); 19 | List list = new List(COUNT); 20 | UnsafeList* uList = UnsafeList.Allocate(COUNT); 21 | 22 | ~ListAddExpand() 23 | { 24 | nList.Dispose(); 25 | UnsafeList.Free(uList); 26 | } 27 | 28 | [Benchmark] 29 | public void ListAdd() 30 | { 31 | for (int i = 0; i < COUNTMAX; i++) 32 | { 33 | list.Add(i); 34 | } 35 | 36 | list.Clear(); 37 | } 38 | 39 | [Benchmark] 40 | public void NativeListAdd() 41 | { 42 | for (int i = 0; i < COUNTMAX; i++) 43 | { 44 | nList.Add(i); 45 | } 46 | 47 | nList.Clear(); 48 | } 49 | 50 | [Benchmark] 51 | public void UnsafeListAdd() 52 | { 53 | for (int i = 0; i < COUNTMAX; i++) 54 | { 55 | UnsafeList.Add(uList, i); 56 | } 57 | 58 | UnsafeList.Clear(uList); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Benchmark/ListIndexOf.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnsafeCollections.Collections.Native; 8 | using UnsafeCollections.Collections.Unsafe; 9 | 10 | namespace Benchmark 11 | { 12 | [MemoryDiagnoser] 13 | public unsafe class ListIndexOf 14 | { 15 | const int COUNT = 32; 16 | 17 | NativeList nList = new NativeList(COUNT); 18 | List list = new List(COUNT); 19 | UnsafeList* uList = UnsafeList.Allocate(COUNT); 20 | 21 | 22 | public ListIndexOf() 23 | { 24 | for (int i = 0; i < COUNT; i++) 25 | { 26 | list.Add(i); 27 | nList.Add(i); 28 | UnsafeList.Add(uList, i); 29 | } 30 | } 31 | 32 | ~ListIndexOf() 33 | { 34 | nList.Dispose(); 35 | UnsafeList.Free(uList); 36 | } 37 | 38 | [Benchmark] 39 | public void ListIndexof() 40 | { 41 | int num = list.IndexOf(COUNT / 3 * 2); 42 | } 43 | 44 | [Benchmark] 45 | public void NativeListIndexOf() 46 | { 47 | int num = nList.IndexOf(COUNT / 3 * 2); 48 | } 49 | 50 | [Benchmark] 51 | public void UnsafeListIndexOf() 52 | { 53 | int num = UnsafeList.IndexOf(uList, COUNT / 3 * 2); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Benchmark/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using BenchmarkDotNet.Running; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Runtime.CompilerServices; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using UnsafeCollections; 10 | using UnsafeCollections.Collections.Native; 11 | using UnsafeCollections.Collections.Unsafe; 12 | 13 | namespace Benchmark 14 | { 15 | class Program 16 | { 17 | static void Main(string[] args) 18 | { 19 | BenchmarkRunner.Run(); 20 | 21 | Console.ReadLine(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Benchmark/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Benchmark")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Benchmark")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("8ff58f17-9e3f-49e0-accf-c2b4f0daa082")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Benchmark/QueueBench.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnsafeCollections.Collections.Native; 8 | using UnsafeCollections.Collections.Native.Concurrent; 9 | using UnsafeCollections.Collections.Unsafe; 10 | 11 | namespace Benchmark 12 | { 13 | public class QueueBench 14 | { 15 | const int COUNT = 32; 16 | 17 | NativeQueue nq = new NativeQueue(COUNT); 18 | Queue q = new Queue(COUNT); 19 | NativeSPSCQueue cq = new NativeSPSCQueue(COUNT); 20 | 21 | public QueueBench() 22 | { 23 | 24 | } 25 | 26 | ~QueueBench() 27 | { 28 | nq.Dispose(); 29 | } 30 | 31 | [Benchmark] 32 | public void QueueAddPeekRemove() 33 | { 34 | for (int i = 0; i < COUNT; i++) 35 | { 36 | q.Enqueue(i); 37 | } 38 | 39 | var peek = q.Peek(); 40 | 41 | for (int i = 0; i < COUNT; i++) 42 | { 43 | var res = q.Dequeue(); 44 | } 45 | } 46 | 47 | [Benchmark] 48 | public void NativeQueueAddPeekRemove() 49 | { 50 | for (int i = 0; i < COUNT; i++) 51 | { 52 | nq.Enqueue(i); 53 | } 54 | 55 | var peek = nq.Peek(); 56 | 57 | for (int i = 0; i < COUNT; i++) 58 | { 59 | var res = nq.Dequeue(); 60 | } 61 | } 62 | 63 | [Benchmark] 64 | public void SPSCQueueAddPeekRemove() 65 | { 66 | for (int i = 0; i < COUNT; i++) 67 | { 68 | cq.Enqueue(i); 69 | } 70 | 71 | var peek = cq.Peek(); 72 | 73 | for (int i = 0; i < COUNT; i++) 74 | { 75 | var res = cq.Dequeue(); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Benchmark/SortedSetBench.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnsafeCollections.Collections.Native; 8 | 9 | namespace Benchmark 10 | { 11 | public class SortedSetBench 12 | { 13 | const int COUNT = 32; 14 | 15 | NativeSortedSet nset = new NativeSortedSet(COUNT); 16 | SortedSet set = new SortedSet(); 17 | 18 | public SortedSetBench() 19 | { 20 | 21 | } 22 | 23 | ~SortedSetBench() 24 | { 25 | nset.Dispose(); 26 | } 27 | 28 | [Benchmark] 29 | public void SortedSetAdd() 30 | { 31 | for (int i = COUNT; i > 0; i--) 32 | { 33 | set.Add(i); 34 | } 35 | 36 | set.Clear(); 37 | } 38 | 39 | [Benchmark] 40 | public void NativeSortedSetAdd() 41 | { 42 | for (int i = COUNT; i > 0; i--) 43 | { 44 | nset.Add(i); 45 | } 46 | 47 | nset.Clear(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Benchmark/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Dennis Corvers 4 | 5 | This software is based on, a modification of and/or an extention 6 | of "UnsafeCollections" originally authored by: 7 | 8 | The MIT License (MIT) 9 | 10 | Copyright (c) 2019 Fredrik Holmstrom 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy 13 | of this software and associated documentation files (the "Software"), to deal 14 | in the Software without restriction, including without limitation the rights 15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the Software is 17 | furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in 20 | all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnsafeCollections 2 | 3 | As this fork diverged too much from the [original](https://github.com/fholm/UnsafeCollections), it became its own repository. 4 | 5 | This project contains various collections that perform no managed memory allocation. It alleviates GC (Garbage Collector) pressure useful for usecases such as Unity. 6 | 7 | Project is targeted as a .Net 2.0 Standard library. Usable in Unity via dll. 8 | 9 | ## Usage 10 | The NativeCollections (under UnsafeCollections/Collections/Native/) are usable just like the matching collections in C# would. The API matches as much as possible with the C# API of the same collection. All of the NativeCollection objects are safe to pass as value. 11 | 12 | You **must** instantiate the collections with any non-default constructor. After you are done using it, you again **must** call the Dispose function. The matching UnsafeCollection objects work similarly, but instead you must call Allocate and Free respectively. 13 | 14 | ## Currently Implemented 15 | 16 | - Array 17 | - List 18 | - LinkedList 19 | - Stack 20 | - Queue 21 | - Bit Set 22 | - Ring Buffer 23 | - Min Heap 24 | - Max Heap 25 | - Dictionary 26 | - HashSet 27 | - SortedDictionary 28 | - SortedSet 29 | - Concurrent SPSC Lockfree Queue 30 | - Concurrent MPSC Lockfree Queue 31 | - Concurrent MPMC Queue (Lockfree with fixed size) 32 | 33 | 34 | ## Build 35 | Use Preprocessor directive UNITY to build the project using the Unity memory allocators instead of the .Net ones. 36 | 37 | The library is usable in both .Net and Unity. 38 | 39 | ## Performance 40 | 41 | Comparison is made for List between .Net List, UnsafeList and NativeList. This is done not only to show the difference between this and the .Net implementation, but also between the Native and Unsafe implementations. 42 | 43 | ### List 44 | 45 | Adding x items to a list, followed by a clear: 46 | | Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | 47 | |-------------- |----------:|---------:|---------:|------:|------:|------:|----------:| 48 | | ListAdd | 196.98 ns | 0.253 ns | 0.236 ns | - | - | - | - | 49 | | NativeListAdd | 76.38 ns | 0.496 ns | 0.464 ns | - | - | - | - | 50 | | UnsafeListAdd | 58.59 ns | 0.293 ns | 0.274 ns | - | - | - | - | 51 | 52 | Adding x items to a list where the list has to resize (followed by a clear): 53 | | Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | 54 | |-------------- |---------:|--------:|--------:|------:|------:|------:|----------:| 55 | | ListAdd | 399.7 ns | 4.60 ns | 4.30 ns | - | - | - | - | 56 | | NativeListAdd | 161.2 ns | 0.13 ns | 0.12 ns | - | - | - | - | 57 | | UnsafeListAdd | 124.9 ns | 0.30 ns | 0.28 ns | - | - | - | - | 58 | 59 | Grabbing the index of a "random" item in the list 60 | | Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated | 61 | |------------------ |---------:|---------:|---------:|------:|------:|------:|----------:| 62 | | ListIndexOf | 28.76 ns | 0.206 ns | 0.193 ns | - | - | - | - | 63 | | NativeListIndexOf | 23.69 ns | 0.038 ns | 0.036 ns | - | - | - | - | 64 | | UnsafeListIndexOf | 23.94 ns | 0.190 ns | 0.178 ns | - | - | - | - | 65 | 66 | 67 | Because the difference in performance between Unsafe and Native is minor, only a comparison between .Net and Native will be made from this point onwards. Do note that the timings for the Unsafe collections are usually slightly lower. 68 | 69 | ### Queue 70 | 71 | Enqueue > Peek > Dequeue operations 72 | | Method | Mean | Error | StdDev | 73 | |------------------------- |---------:|--------:|--------:| 74 | | QueueAddPeekRemove | 444.3 ns | 0.37 ns | 0.35 ns | 75 | | NativeQueueAddPeekRemove | 194.4 ns | 1.47 ns | 1.23 ns | 76 | | SPSCQueueAddPeekRemove | 219.2 ns | 0.19 ns | 0.17 ns | 77 | 78 | ### Sorted Set 79 | 80 | SortedSet Add in reverse order (worst case) 81 | | Method | Mean | Error | StdDev | 82 | |------------------- |---------:|----------:|----------:| 83 | | SortedSetAdd | 1.118 μs | 0.0042 μs | 0.0040 μs | 84 | | NativeSortedSetAdd | 1.964 μs | 0.0104 μs | 0.0098 μs | 85 | 86 | ### Dictionary 87 | 88 | Dictionary Add followed by Remove 89 | | Method | Mean | Error | StdDev | 90 | |-------------------- |---------:|--------:|--------:| 91 | | DictionaryAdd | 580.0 ns | 0.82 ns | 0.73 ns | 92 | | NativeDictionaryAdd | 461.8 ns | 2.82 ns | 2.64 ns | 93 | -------------------------------------------------------------------------------- /UnsafeCollections.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.1300 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnsafeCollections", "UnsafeCollections\UnsafeCollections.csproj", "{FA56C721-6BFD-4C16-BC65-4D9981A9D98E}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnsafeCollectionsTests", "UnsafeCollectionsTests\UnsafeCollectionsTests.csproj", "{14A281B0-E4B8-420B-ABE2-F03217A89ED0}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmark", "Benchmark\Benchmark.csproj", "{8FF58F17-9E3F-49E0-ACCF-C2B4F0DAA082}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {FA56C721-6BFD-4C16-BC65-4D9981A9D98E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {FA56C721-6BFD-4C16-BC65-4D9981A9D98E}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {FA56C721-6BFD-4C16-BC65-4D9981A9D98E}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {FA56C721-6BFD-4C16-BC65-4D9981A9D98E}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {14A281B0-E4B8-420B-ABE2-F03217A89ED0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {14A281B0-E4B8-420B-ABE2-F03217A89ED0}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {14A281B0-E4B8-420B-ABE2-F03217A89ED0}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {14A281B0-E4B8-420B-ABE2-F03217A89ED0}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {8FF58F17-9E3F-49E0-ACCF-C2B4F0DAA082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {8FF58F17-9E3F-49E0-ACCF-C2B4F0DAA082}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {8FF58F17-9E3F-49E0-ACCF-C2B4F0DAA082}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {8FF58F17-9E3F-49E0-ACCF-C2B4F0DAA082}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {37849F75-32F1-4413-B1DC-D80F1F7B8A95} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /UnsafeCollections/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnsafeCollectionsTests")] -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/Concurrent/NativeMPMCQueue.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Concurrent; 28 | using System.Collections.Generic; 29 | using System.Diagnostics; 30 | using UnsafeCollections.Collections.Unsafe.Concurrent; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native.Concurrent 34 | { 35 | [DebuggerDisplay("Count = {Count}")] 36 | [DebuggerTypeProxy(typeof(NativeReadOnlyCollectionDebugView<>))] 37 | public unsafe struct NativeMPMCQueue : INativeReadOnlyCollection, IProducerConsumerCollection where T : unmanaged 38 | { 39 | private UnsafeMPMCQueue* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Count 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeMPMCQueue.GetCount(m_inner); 55 | } 56 | } 57 | public int Capacity 58 | { 59 | get 60 | { 61 | if (m_inner == null) 62 | throw new NullReferenceException(); 63 | return UnsafeMPMCQueue.GetCapacity(m_inner); 64 | } 65 | } 66 | public bool IsEmpty 67 | { 68 | get 69 | { 70 | if (m_inner == null) 71 | throw new NullReferenceException(); 72 | return UnsafeMPMCQueue.IsEmpty(m_inner); 73 | } 74 | } 75 | 76 | bool ICollection.IsSynchronized => false; 77 | object ICollection.SyncRoot => throw new NotSupportedException(); 78 | 79 | 80 | public NativeMPMCQueue(int segmentSize) 81 | { 82 | m_inner = UnsafeMPMCQueue.Allocate(segmentSize); 83 | } 84 | 85 | public NativeMPMCQueue(int segmentSize, bool fixedSize) 86 | { 87 | m_inner = UnsafeMPMCQueue.Allocate(segmentSize, fixedSize); 88 | } 89 | 90 | 91 | public bool TryEnqueue(T item) 92 | { 93 | return UnsafeMPMCQueue.TryEnqueue(m_inner, item); 94 | } 95 | 96 | public bool TryDequeue(out T result) 97 | { 98 | return UnsafeMPMCQueue.TryDequeue(m_inner, out result); 99 | } 100 | 101 | public bool TryPeek(out T result) 102 | { 103 | return UnsafeMPMCQueue.TryPeek(m_inner, out result); 104 | } 105 | 106 | public void Clear() 107 | { 108 | UnsafeMPMCQueue.Clear(m_inner); 109 | } 110 | 111 | 112 | bool IProducerConsumerCollection.TryAdd(T item) 113 | { 114 | return TryEnqueue(item); 115 | } 116 | 117 | bool IProducerConsumerCollection.TryTake(out T item) 118 | { 119 | return TryDequeue(out item); 120 | } 121 | 122 | 123 | public void CopyTo(T[] array, int arrayIndex) 124 | { 125 | if (array == null) 126 | throw new ArgumentNullException(nameof(array)); 127 | 128 | if ((uint)arrayIndex > array.Length) 129 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 130 | 131 | if (array.Length - arrayIndex < Count) 132 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 133 | 134 | if (array.Length == 0) 135 | return; 136 | 137 | UnsafeMPMCQueue.ToArray(m_inner).CopyTo(array, arrayIndex); 138 | } 139 | 140 | public T[] ToArray() 141 | { 142 | return UnsafeMPMCQueue.ToArray(m_inner); 143 | } 144 | 145 | 146 | void ICollection.CopyTo(Array array, int index) 147 | { 148 | if (array is T[] szArray) 149 | { 150 | CopyTo(szArray, index); 151 | return; 152 | } 153 | 154 | if (array == null) 155 | throw new ArgumentNullException(nameof(array)); 156 | 157 | ToArray().CopyTo(array, index); 158 | } 159 | 160 | public UnsafeMPMCQueue.Enumerator GetEnumerator() 161 | { 162 | return UnsafeMPMCQueue.GetEnumerator(m_inner); 163 | } 164 | IEnumerator IEnumerable.GetEnumerator() 165 | { 166 | return UnsafeMPMCQueue.GetEnumerator(m_inner); 167 | } 168 | IEnumerator IEnumerable.GetEnumerator() 169 | { 170 | return UnsafeMPMCQueue.GetEnumerator(m_inner); 171 | } 172 | 173 | #if UNITY 174 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 175 | #endif 176 | public void Dispose() 177 | { 178 | UnsafeMPMCQueue.Free(m_inner); 179 | m_inner = null; 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/Concurrent/NativeMPSCQueue.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Concurrent; 28 | using System.Collections.Generic; 29 | using System.Diagnostics; 30 | using UnsafeCollections.Collections.Unsafe.Concurrent; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native.Concurrent 34 | { 35 | [DebuggerDisplay("Count = {Count}")] 36 | [DebuggerTypeProxy(typeof(NativeReadOnlyCollectionDebugView<>))] 37 | public unsafe struct NativeMPSCQueue : INativeReadOnlyCollection, IProducerConsumerCollection where T : unmanaged 38 | { 39 | private UnsafeMPSCQueue* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Count 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeMPSCQueue.GetCount(m_inner); 55 | } 56 | } 57 | public int Capacity 58 | { 59 | get 60 | { 61 | if (m_inner == null) 62 | throw new NullReferenceException(); 63 | return UnsafeMPSCQueue.GetCapacity(m_inner); 64 | } 65 | } 66 | public bool IsEmpty 67 | { 68 | get 69 | { 70 | if (m_inner == null) 71 | throw new NullReferenceException(); 72 | return UnsafeMPSCQueue.IsEmpty(m_inner); 73 | } 74 | } 75 | 76 | bool ICollection.IsSynchronized => false; 77 | object ICollection.SyncRoot => throw new NotSupportedException(); 78 | 79 | 80 | public NativeMPSCQueue(int capacity) 81 | { 82 | m_inner = UnsafeMPSCQueue.Allocate(capacity); 83 | } 84 | 85 | 86 | public bool TryEnqueue(T item) 87 | { 88 | return UnsafeMPSCQueue.TryEnqueue(m_inner, item); 89 | } 90 | 91 | public T Dequeue() 92 | { 93 | return UnsafeMPSCQueue.Dequeue(m_inner); 94 | } 95 | 96 | public bool TryDequeue(out T item) 97 | { 98 | return UnsafeMPSCQueue.TryDequeue(m_inner, out item); 99 | } 100 | 101 | public bool TryPeek(out T item) 102 | { 103 | return UnsafeMPSCQueue.TryPeek(m_inner, out item); 104 | } 105 | 106 | public void Clear() 107 | { 108 | UnsafeMPSCQueue.Clear(m_inner); 109 | } 110 | 111 | 112 | bool IProducerConsumerCollection.TryAdd(T item) 113 | { 114 | return TryEnqueue(item); 115 | } 116 | 117 | bool IProducerConsumerCollection.TryTake(out T item) 118 | { 119 | return TryDequeue(out item); 120 | } 121 | 122 | 123 | public void CopyTo(T[] array, int arrayIndex) 124 | { 125 | if (array == null) 126 | throw new ArgumentNullException(nameof(array)); 127 | 128 | if ((uint)arrayIndex > array.Length) 129 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 130 | 131 | if (array.Length - arrayIndex < Count) 132 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 133 | 134 | if (array.Length == 0) 135 | return; 136 | 137 | UnsafeMPSCQueue.ToArray(m_inner).CopyTo(array, arrayIndex); 138 | } 139 | 140 | void ICollection.CopyTo(Array array, int index) 141 | { 142 | if (array is T[] szArray) 143 | { 144 | CopyTo(szArray, index); 145 | return; 146 | } 147 | 148 | if (array == null) 149 | throw new ArgumentNullException(nameof(array)); 150 | 151 | ToArray().CopyTo(array, index); 152 | } 153 | 154 | public T[] ToArray() 155 | { 156 | return UnsafeMPSCQueue.ToArray(m_inner); 157 | } 158 | 159 | 160 | public UnsafeMPSCQueue.Enumerator GetEnumerator() 161 | { 162 | return UnsafeMPSCQueue.GetEnumerator(m_inner); 163 | } 164 | IEnumerator IEnumerable.GetEnumerator() 165 | { 166 | return UnsafeMPSCQueue.GetEnumerator(m_inner); 167 | } 168 | IEnumerator IEnumerable.GetEnumerator() 169 | { 170 | return UnsafeMPSCQueue.GetEnumerator(m_inner); 171 | } 172 | 173 | #if UNITY 174 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 175 | #endif 176 | public void Dispose() 177 | { 178 | UnsafeMPSCQueue.Free(m_inner); 179 | m_inner = null; 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/Concurrent/NativeSPSCQueue.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Concurrent; 28 | using System.Collections.Generic; 29 | using System.Diagnostics; 30 | using UnsafeCollections.Collections.Unsafe.Concurrent; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native.Concurrent 34 | { 35 | [DebuggerDisplay("Count = {Count}")] 36 | [DebuggerTypeProxy(typeof(NativeReadOnlyCollectionDebugView<>))] 37 | public unsafe struct NativeSPSCQueue : INativeReadOnlyCollection, IProducerConsumerCollection where T : unmanaged 38 | { 39 | private UnsafeSPSCQueue* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Count 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeSPSCQueue.GetCount(m_inner); 55 | } 56 | } 57 | public int Capacity 58 | { 59 | get 60 | { 61 | if (m_inner == null) 62 | throw new NullReferenceException(); 63 | return UnsafeSPSCQueue.GetCapacity(m_inner); 64 | } 65 | } 66 | public bool IsEmpty 67 | { 68 | get 69 | { 70 | if (m_inner == null) 71 | throw new NullReferenceException(); 72 | return UnsafeSPSCQueue.IsEmpty(m_inner); 73 | } 74 | } 75 | 76 | bool ICollection.IsSynchronized => false; 77 | object ICollection.SyncRoot => throw new NotSupportedException(); 78 | 79 | 80 | public NativeSPSCQueue(int capacity) 81 | { 82 | m_inner = UnsafeSPSCQueue.Allocate(capacity); 83 | } 84 | 85 | public void Enqueue(T item) 86 | { 87 | UnsafeSPSCQueue.Enqueue(m_inner, item); 88 | } 89 | 90 | public bool TryEnqueue(T item) 91 | { 92 | return UnsafeSPSCQueue.TryEnqueue(m_inner, item); 93 | } 94 | 95 | public T Dequeue() 96 | { 97 | return UnsafeSPSCQueue.Dequeue(m_inner); 98 | } 99 | 100 | public bool TryDequeue(out T item) 101 | { 102 | return UnsafeSPSCQueue.TryDequeue(m_inner, out item); 103 | } 104 | 105 | public T Peek() 106 | { 107 | return UnsafeSPSCQueue.Peek(m_inner); 108 | } 109 | 110 | public bool TryPeek(out T item) 111 | { 112 | return UnsafeSPSCQueue.TryPeek(m_inner, out item); 113 | } 114 | 115 | public void Clear() 116 | { 117 | UnsafeSPSCQueue.Clear(m_inner); 118 | } 119 | 120 | 121 | bool IProducerConsumerCollection.TryAdd(T item) 122 | { 123 | return TryEnqueue(item); 124 | } 125 | 126 | bool IProducerConsumerCollection.TryTake(out T item) 127 | { 128 | return TryDequeue(out item); 129 | } 130 | 131 | 132 | public void CopyTo(T[] array, int arrayIndex) 133 | { 134 | if (array == null) 135 | throw new ArgumentNullException(nameof(array)); 136 | 137 | if ((uint)arrayIndex > array.Length) 138 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 139 | 140 | if (array.Length - arrayIndex < Count) 141 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 142 | 143 | if (array.Length == 0) 144 | return; 145 | 146 | UnsafeSPSCQueue.ToArray(m_inner).CopyTo(array, arrayIndex); 147 | } 148 | 149 | void ICollection.CopyTo(Array array, int index) 150 | { 151 | if (array is T[] szArray) 152 | { 153 | CopyTo(szArray, index); 154 | return; 155 | } 156 | 157 | if (array == null) 158 | throw new ArgumentNullException(nameof(array)); 159 | 160 | ToArray().CopyTo(array, index); 161 | } 162 | 163 | public T[] ToArray() 164 | { 165 | return UnsafeSPSCQueue.ToArray(m_inner); 166 | } 167 | 168 | 169 | public UnsafeSPSCQueue.Enumerator GetEnumerator() 170 | { 171 | return UnsafeSPSCQueue.GetEnumerator(m_inner); 172 | } 173 | IEnumerator IEnumerable.GetEnumerator() 174 | { 175 | return UnsafeSPSCQueue.GetEnumerator(m_inner); 176 | } 177 | IEnumerator IEnumerable.GetEnumerator() 178 | { 179 | return UnsafeSPSCQueue.GetEnumerator(m_inner); 180 | } 181 | 182 | #if UNITY 183 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 184 | #endif 185 | public void Dispose() 186 | { 187 | UnsafeSPSCQueue.Free(m_inner); 188 | m_inner = null; 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/INativeArray.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | 29 | namespace UnsafeCollections.Collections.Native 30 | { 31 | public interface INativeArray : IDisposable, IEnumerable, IEnumerable where T : unmanaged 32 | { 33 | /// 34 | /// Returns 'True' if the underlying buffer is allocated. 35 | /// 36 | bool IsCreated { get; } 37 | 38 | /// 39 | /// The number of items in the collection 40 | /// 41 | int Length { get; } 42 | 43 | /// 44 | /// Copies a collection into an array. 45 | /// 46 | T[] ToArray(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/INativeCollection.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | 29 | namespace UnsafeCollections.Collections.Native 30 | { 31 | public interface INativeCollection : ICollection, IEnumerable, IEnumerable, IDisposable where T : unmanaged 32 | { 33 | /// 34 | /// Returns 'True' if the underlying buffer is allocated. 35 | /// 36 | bool IsCreated { get; } 37 | 38 | /// 39 | /// Copies the collection into a NativeArray. 40 | /// 41 | NativeArray ToNativeArray(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/INativeDictionary.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | 28 | namespace UnsafeCollections.Collections.Native 29 | { 30 | public interface INativeDictionary : IDictionary, IDisposable 31 | where K : unmanaged 32 | where V : unmanaged 33 | { 34 | 35 | /// 36 | /// Returns 'True' if the underlying buffer is allocated. 37 | /// 38 | bool IsCreated { get; } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/INativeReadOnlyCollection.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Text; 29 | 30 | namespace UnsafeCollections.Collections.Native 31 | { 32 | public interface INativeReadOnlyCollection : IReadOnlyCollection, IEnumerable, IDisposable where T : unmanaged 33 | { 34 | /// 35 | /// Returns 'True' if the underlying buffer is allocated. 36 | /// 37 | bool IsCreated { get; } 38 | 39 | /// 40 | /// Copies the collection into the provided array. 41 | /// 42 | void CopyTo(T[] array, int arrayIndex); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/NativeArray.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Runtime.CompilerServices; 30 | using UnsafeCollections.Collections.Unsafe; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | #if UNITY 33 | using Unity.Collections.LowLevel.Unsafe; 34 | #endif 35 | 36 | namespace UnsafeCollections.Collections.Native 37 | { 38 | [DebuggerDisplay("Length = {Length}")] 39 | [DebuggerTypeProxy(typeof(NativeArrayDebugView<>))] 40 | public unsafe partial struct NativeArray : INativeArray where T : unmanaged 41 | { 42 | private UnsafeArray* m_inner; 43 | 44 | public bool IsCreated 45 | { 46 | get 47 | { 48 | return m_inner != null; 49 | } 50 | } 51 | public int Length 52 | { 53 | get 54 | { 55 | if (m_inner == null) 56 | throw new NullReferenceException(); 57 | return UnsafeArray.GetLength(m_inner); 58 | } 59 | } 60 | 61 | 62 | public NativeArray(int length) 63 | { 64 | m_inner = UnsafeArray.Allocate(length); 65 | } 66 | 67 | public NativeArray(T[] array) 68 | { 69 | m_inner = UnsafeArray.Allocate(array.Length); 70 | 71 | Copy(array, this, array.Length); 72 | } 73 | 74 | public NativeArray(NativeArray array) 75 | { 76 | m_inner = UnsafeArray.Allocate(array.Length); 77 | 78 | Copy(array, this); 79 | } 80 | 81 | public T this[int index] 82 | { 83 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 84 | get 85 | { 86 | return UnsafeArray.Get(m_inner, index); 87 | } 88 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 89 | set 90 | { 91 | UnsafeArray.Set(m_inner, index, value); 92 | } 93 | } 94 | 95 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 96 | public ref T GetRef(int index) 97 | { 98 | return ref UnsafeArray.GetRef(m_inner, index); 99 | } 100 | 101 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 102 | internal UnsafeArray* GetInnerCollection() 103 | { 104 | return m_inner; 105 | } 106 | 107 | public static void Copy(NativeArray src, NativeArray dst) 108 | { 109 | Copy(src, 0, dst, 0, src.Length); 110 | } 111 | public static void Copy(NativeArray src, NativeArray dst, int length) 112 | { 113 | Copy(src, 0, dst, 0, length); 114 | } 115 | public static void Copy(NativeArray src, int srcIndex, NativeArray dst, int dstIndex, int length) 116 | { 117 | UnsafeArray.Copy(src.m_inner, srcIndex, dst.m_inner, dstIndex, length); 118 | } 119 | 120 | public static void Copy(NativeArray src, T[] dst) 121 | { 122 | Copy(src, 0, dst, 0, src.Length); 123 | } 124 | public static void Copy(NativeArray src, T[] dst, int length) 125 | { 126 | Copy(src, 0, dst, 0, length); 127 | } 128 | public static void Copy(NativeArray src, int srcIndex, T[] dst, int dstIndex, int length) 129 | { 130 | UDebug.Assert(src.IsCreated); 131 | UDebug.Assert(src.Length >= srcIndex + length); 132 | UDebug.Assert(dst != null); 133 | UDebug.Assert(dst.Length >= dstIndex + length); 134 | 135 | fixed (void* ptr = dst) 136 | Memory.ArrayCopy(UnsafeArray.GetBuffer(src.m_inner), 0, ptr, 0, length); 137 | } 138 | 139 | public static void Copy(T[] src, NativeArray dst) 140 | { 141 | Copy(src, 0, dst, 0, src.Length); 142 | } 143 | public static void Copy(T[] src, NativeArray dst, int length) 144 | { 145 | Copy(src, 0, dst, 0, length); 146 | } 147 | public static void Copy(T[] src, int srcIndex, NativeArray dst, int dstIndex, int length) 148 | { 149 | UDebug.Assert(src != null); 150 | UDebug.Assert(src.Length >= srcIndex + length); 151 | UDebug.Assert(dst.IsCreated); 152 | UDebug.Assert(dst.Length >= dstIndex + length); 153 | 154 | fixed (void* ptr = src) 155 | Memory.ArrayCopy(ptr, 0, UnsafeArray.GetBuffer(dst.m_inner), 0, length); 156 | } 157 | 158 | #if UNITY 159 | [WriteAccessRequired] 160 | #endif 161 | public void CopyFrom(T[] array) 162 | { 163 | Copy(array, 0, this, 0, array.Length); 164 | } 165 | #if UNITY 166 | [WriteAccessRequired] 167 | #endif 168 | public void CopyFrom(NativeArray array) 169 | { 170 | Copy(array, this); 171 | } 172 | public void CopyTo(T[] array) 173 | { 174 | Copy(this, array, Length); 175 | } 176 | public void CopyTo(NativeArray array) 177 | { 178 | Copy(this, array); 179 | } 180 | 181 | public int FindIndex(Func predicate) 182 | { 183 | return UnsafeArray.FindIndex(m_inner, predicate); 184 | } 185 | public int FindLastIndex(Func predicate) 186 | { 187 | return UnsafeArray.FindLastIndex(m_inner, predicate); 188 | } 189 | 190 | public T[] ToArray() 191 | { 192 | if (Length == 0) 193 | return Array.Empty(); 194 | 195 | var arr = new T[Length]; 196 | 197 | Copy(this, arr, arr.Length); 198 | 199 | return arr; 200 | } 201 | 202 | public UnsafeArray.Enumerator GetEnumerator() 203 | { 204 | return UnsafeArray.GetEnumerator(m_inner); 205 | } 206 | IEnumerator IEnumerable.GetEnumerator() 207 | { 208 | return UnsafeArray.GetEnumerator(m_inner); 209 | } 210 | IEnumerator IEnumerable.GetEnumerator() 211 | { 212 | return UnsafeArray.GetEnumerator(m_inner); 213 | } 214 | 215 | #if UNITY 216 | [WriteAccessRequired] 217 | #endif 218 | public void Dispose() 219 | { 220 | UnsafeArray.Free(m_inner); 221 | m_inner = null; 222 | } 223 | } 224 | 225 | // Partial class is used to achieve the same syntax as .NET's Array.Empty 226 | public unsafe partial struct NativeArray 227 | { 228 | /// 229 | /// Returns an empty array. 230 | /// 231 | public static NativeArray Empty() where T : unmanaged 232 | { 233 | return new NativeArray(0); 234 | } 235 | } 236 | 237 | // Extension methods are used to add extra constraints to 238 | public unsafe static class NativeArrayExtensions 239 | { 240 | public static bool Contains(this NativeArray array, T item) where T : unmanaged, IEquatable 241 | { 242 | return UnsafeArray.IndexOf(array.GetInnerCollection(), item) > -1; 243 | } 244 | 245 | public static int IndexOf(this NativeArray array, T item) where T : unmanaged, IEquatable 246 | { 247 | return UnsafeArray.IndexOf(array.GetInnerCollection(), item); 248 | } 249 | 250 | public static int LastIndexOf(this NativeArray array, T item) where T : unmanaged, IEquatable 251 | { 252 | return UnsafeArray.LastIndexOf(array.GetInnerCollection(), item); 253 | } 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/NativeBitSet.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Runtime.CompilerServices; 30 | using UnsafeCollections.Collections.Unsafe; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native 34 | { 35 | [DebuggerDisplay("Size = {Size}")] 36 | [DebuggerTypeProxy(typeof(NativeBitSetDebugView))] 37 | public unsafe struct NativeBitSet : IDisposable, IEnumerable, IEnumerable<(int bit, bool set)> 38 | { 39 | private UnsafeBitSet* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Size 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeBitSet.GetSize(m_inner); 55 | } 56 | } 57 | 58 | public bool this[int index] 59 | { 60 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 61 | get 62 | { 63 | return UnsafeBitSet.IsSet(m_inner, index); 64 | } 65 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 66 | set 67 | { 68 | UnsafeBitSet.Set(m_inner, index, value); 69 | } 70 | } 71 | 72 | 73 | public NativeBitSet(int size) 74 | { 75 | m_inner = UnsafeBitSet.Allocate(size); 76 | } 77 | 78 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 79 | public bool GetValue(int index) 80 | { 81 | return this[index]; 82 | } 83 | 84 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 85 | public void SetValue(bool value, int index) 86 | { 87 | this[index] = value; 88 | } 89 | 90 | public void Clear() 91 | { 92 | UnsafeBitSet.Clear(m_inner); 93 | } 94 | 95 | public byte[] ToArray() 96 | { 97 | var arr = new byte[Size]; 98 | 99 | int i = 0; 100 | foreach (var (bit, set) in GetEnumerator()) 101 | arr[i++] = (byte)(set ? 1 : 0); 102 | 103 | return arr; 104 | } 105 | 106 | public UnsafeBitSet.Enumerator GetEnumerator() 107 | { 108 | return UnsafeBitSet.GetEnumerator(m_inner); 109 | } 110 | IEnumerator<(int bit, bool set)> IEnumerable<(int bit, bool set)>.GetEnumerator() 111 | { 112 | return UnsafeBitSet.GetEnumerator(m_inner); 113 | } 114 | IEnumerator IEnumerable.GetEnumerator() 115 | { 116 | return UnsafeBitSet.GetEnumerator(m_inner); 117 | } 118 | 119 | #if UNITY 120 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 121 | #endif 122 | public void Dispose() 123 | { 124 | UnsafeBitSet.Free(m_inner); 125 | m_inner = null; 126 | } 127 | 128 | 129 | public static NativeBitSet operator |(NativeBitSet set, NativeBitSet other) 130 | { 131 | UnsafeBitSet.Or(set.m_inner, other.m_inner); 132 | return set; 133 | } 134 | 135 | public static NativeBitSet operator &(NativeBitSet set, NativeBitSet other) 136 | { 137 | UnsafeBitSet.And(set.m_inner, other.m_inner); 138 | return set; 139 | } 140 | 141 | public static NativeBitSet operator ^(NativeBitSet set, NativeBitSet other) 142 | { 143 | UnsafeBitSet.Xor(set.m_inner, other.m_inner); 144 | return set; 145 | } 146 | 147 | public static bool operator ==(NativeBitSet a, NativeBitSet b) 148 | { 149 | return UnsafeBitSet.AreEqual(a.m_inner, b.m_inner); 150 | } 151 | 152 | public static bool operator !=(NativeBitSet a, NativeBitSet b) 153 | { 154 | return !(a == b); 155 | } 156 | 157 | // These two are required to stop the compiler from complaining. 158 | public override bool Equals(object obj) 159 | { 160 | if (!(obj is NativeBitSet)) 161 | return false; 162 | 163 | return this == (NativeBitSet)obj; 164 | } 165 | 166 | public override int GetHashCode() 167 | { 168 | return base.GetHashCode(); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/NativeHashSet.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using UnsafeCollections.Collections.Unsafe; 30 | using UnsafeCollections.Debug.TypeProxies; 31 | 32 | namespace UnsafeCollections.Collections.Native 33 | { 34 | [DebuggerDisplay("Count = {Count}")] 35 | [DebuggerTypeProxy(typeof(NativeReadOnlyCollectionDebugView<>))] 36 | public unsafe struct NativeHashSet : INativeReadOnlyCollection, INativeCollection 37 | where T : unmanaged, IEquatable 38 | { 39 | private UnsafeHashSet* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Count 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeHashSet.GetCount(m_inner); 55 | } 56 | } 57 | public int Capacity 58 | { 59 | get 60 | { 61 | if (m_inner == null) 62 | throw new NullReferenceException(); 63 | return UnsafeHashSet.GetCapacity(m_inner); 64 | } 65 | } 66 | public bool IsFixedSize 67 | { 68 | get 69 | { 70 | if (m_inner == null) 71 | throw new NullReferenceException(); 72 | return UnsafeHashSet.IsFixedSize(m_inner); 73 | } 74 | } 75 | 76 | public bool IsReadOnly => false; 77 | 78 | public NativeHashSet(int capacity) 79 | { 80 | m_inner = UnsafeHashSet.Allocate(capacity, false); 81 | } 82 | 83 | public NativeHashSet(int capacity, bool fixedSize) 84 | { 85 | m_inner = UnsafeHashSet.Allocate(capacity, fixedSize); 86 | } 87 | 88 | 89 | public void Add(T item) 90 | { 91 | UnsafeHashSet.Add(m_inner, item); 92 | } 93 | 94 | public void Clear() 95 | { 96 | UnsafeHashSet.Clear(m_inner); 97 | } 98 | 99 | public bool Contains(T item) 100 | { 101 | return UnsafeHashSet.Contains(m_inner, item); 102 | } 103 | 104 | public bool Remove(T item) 105 | { 106 | return UnsafeHashSet.Remove(m_inner, item); 107 | } 108 | 109 | 110 | public void IntersectsWith(NativeHashSet other) 111 | { 112 | UnsafeHashSet.IntersectsWith(m_inner, other.m_inner); 113 | } 114 | 115 | public void UnionWith(NativeHashSet other) 116 | { 117 | UnsafeHashSet.UnionWith(m_inner, other.m_inner); 118 | } 119 | 120 | public void ExceptWith(NativeHashSet other) 121 | { 122 | UnsafeHashSet.ExceptWith(m_inner, other.m_inner); 123 | } 124 | 125 | public void SymmetricExcept(NativeHashSet other) 126 | { 127 | UnsafeHashSet.SymmetricExcept(m_inner, other.m_inner); 128 | } 129 | 130 | 131 | public T[] ToArray() 132 | { 133 | if (Count == 0) 134 | return Array.Empty(); 135 | 136 | var arr = new T[Count]; 137 | 138 | CopyTo(arr, 0); 139 | 140 | return arr; 141 | } 142 | 143 | public void CopyTo(T[] array, int arrayIndex) 144 | { 145 | if (array == null) 146 | throw new ArgumentNullException(nameof(array)); 147 | 148 | if ((uint)arrayIndex > array.Length) 149 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 150 | 151 | if (array.Length - arrayIndex < Count) 152 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 153 | 154 | if (array.Length == 0) 155 | return; 156 | 157 | fixed (void* ptr = array) 158 | UnsafeHashSet.CopyTo(m_inner, ptr, arrayIndex); 159 | } 160 | 161 | public NativeArray ToNativeArray() 162 | { 163 | if (Count == 0) 164 | return NativeArray.Empty(); 165 | 166 | var arr = new NativeArray(Count); 167 | UnsafeHashSet.CopyTo(m_inner, UnsafeArray.GetBuffer(arr.GetInnerCollection()), 0); 168 | 169 | return arr; 170 | } 171 | 172 | 173 | public UnsafeHashSet.Enumerator GetEnumerator() 174 | { 175 | return UnsafeHashSet.GetEnumerator(m_inner); 176 | } 177 | IEnumerator IEnumerable.GetEnumerator() 178 | { 179 | return UnsafeHashSet.GetEnumerator(m_inner); 180 | } 181 | IEnumerator IEnumerable.GetEnumerator() 182 | { 183 | return UnsafeHashSet.GetEnumerator(m_inner); 184 | } 185 | 186 | #if UNITY 187 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 188 | #endif 189 | public void Dispose() 190 | { 191 | UnsafeHashSet.Free(m_inner); 192 | m_inner = null; 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/NativeLinkedList.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Runtime.CompilerServices; 30 | using UnsafeCollections.Collections.Unsafe; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native 34 | { 35 | [DebuggerDisplay("Count = {Count}")] 36 | [DebuggerTypeProxy(typeof(NativeCollectionDebugView<>))] 37 | public unsafe struct NativeLinkedList : INativeCollection, INativeReadOnlyCollection where T : unmanaged 38 | { 39 | private UnsafeLinkedList* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Count 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeLinkedList.GetCount(m_inner); 55 | } 56 | } 57 | 58 | bool ICollection.IsReadOnly => false; 59 | 60 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 61 | internal UnsafeLinkedList* GetInnerCollection() 62 | { 63 | return m_inner; 64 | } 65 | 66 | /// 67 | /// Constructor for . 68 | /// 69 | /// Dummy value that does nothing. 70 | public NativeLinkedList(bool create) 71 | { 72 | m_inner = UnsafeLinkedList.Allocate(); 73 | } 74 | 75 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 76 | public T GetFirst() 77 | { 78 | return UnsafeLinkedList.GetFirst(m_inner); 79 | } 80 | 81 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 82 | public T GetLast() 83 | { 84 | return UnsafeLinkedList.GetLast(m_inner); 85 | } 86 | 87 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 88 | public void AddFirst(T item) 89 | { 90 | UnsafeLinkedList.AddFirst(m_inner, item); 91 | } 92 | 93 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 94 | public void AddLast(T item) 95 | { 96 | UnsafeLinkedList.AddLast(m_inner, item); 97 | } 98 | 99 | /// 100 | /// Adds a node to the after the given . 101 | /// The will be invalidated. 102 | /// 103 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 104 | public void AddAfter(ref Node previousNode, T item) 105 | { 106 | UnsafeLinkedList.AddAfter(m_inner, previousNode._node, item); 107 | previousNode._node = null; 108 | } 109 | 110 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 111 | public bool Remove(ref Node node) 112 | { 113 | return UnsafeLinkedList.Remove(m_inner, ref node._node); 114 | } 115 | 116 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 117 | public void RemoveFirst() 118 | { 119 | UnsafeLinkedList.RemoveFirst(m_inner); 120 | } 121 | 122 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 123 | public void RemoveLast() 124 | { 125 | UnsafeLinkedList.RemoveLast(m_inner); 126 | } 127 | 128 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 129 | public void Clear() 130 | { 131 | UnsafeLinkedList.Clear(m_inner); 132 | } 133 | 134 | public T[] ToArray() 135 | { 136 | if (Count == 0) 137 | return Array.Empty(); 138 | 139 | var arr = new T[Count]; 140 | 141 | CopyTo(arr, 0); 142 | 143 | return arr; 144 | } 145 | 146 | public void CopyTo(T[] array, int arrayIndex) 147 | { 148 | if (array == null) 149 | throw new ArgumentNullException(nameof(array)); 150 | 151 | if ((uint)arrayIndex > array.Length) 152 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 153 | 154 | if (array.Length - arrayIndex < Count) 155 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 156 | 157 | if (array.Length == 0) 158 | return; 159 | 160 | fixed (void* ptr = array) 161 | UnsafeLinkedList.CopyTo(m_inner, ptr, arrayIndex); 162 | } 163 | 164 | public NativeArray ToNativeArray() 165 | { 166 | if (Count == 0) 167 | return NativeArray.Empty(); 168 | 169 | var arr = new NativeArray(Count); 170 | UnsafeLinkedList.CopyTo(m_inner, UnsafeArray.GetBuffer(arr.GetInnerCollection()), 0); 171 | 172 | return arr; 173 | } 174 | 175 | public UnsafeLinkedList.Enumerator GetEnumerator() 176 | { 177 | return UnsafeLinkedList.GetEnumerator(m_inner); 178 | } 179 | IEnumerator IEnumerable.GetEnumerator() 180 | { 181 | return UnsafeLinkedList.GetEnumerator(m_inner); 182 | } 183 | IEnumerator IEnumerable.GetEnumerator() 184 | { 185 | return UnsafeLinkedList.GetEnumerator(m_inner); 186 | } 187 | 188 | void ICollection.Add(T item) 189 | { 190 | UnsafeLinkedList.AddLast(m_inner, item); 191 | } 192 | 193 | bool ICollection.Contains(T item) 194 | { 195 | var eq = EqualityComparer.Default; 196 | 197 | foreach (var enumItem in UnsafeLinkedList.GetEnumerator(m_inner)) 198 | { 199 | if (eq.Equals(item, enumItem)) 200 | return true; 201 | } 202 | return false; 203 | } 204 | 205 | bool ICollection.Remove(T item) 206 | { 207 | return UnsafeLinkedList.RemoveSlow(m_inner, item); 208 | } 209 | 210 | #if UNITY 211 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 212 | #endif 213 | public void Dispose() 214 | { 215 | UnsafeLinkedList.Free(m_inner); 216 | m_inner = null; 217 | } 218 | 219 | [DebuggerDisplay("Item = {Item}")] 220 | public struct Node 221 | { 222 | internal UnsafeLinkedList.Node* _node; 223 | 224 | public bool IsValid 225 | { 226 | get => _node != null; 227 | } 228 | public T Item 229 | { 230 | get => UnsafeLinkedList.Node.GetItem(_node); 231 | 232 | set => UnsafeLinkedList.Node.SetItem(_node, value); 233 | } 234 | 235 | internal Node(UnsafeLinkedList.Node* node) 236 | { 237 | _node = node; 238 | } 239 | } 240 | } 241 | 242 | // Extension methods are used to add extra constraints to 243 | public unsafe static class NativeLinkedListExtensions 244 | { 245 | public static bool Contains(this NativeLinkedList linkedList, T item) 246 | where T : unmanaged, IEquatable 247 | { 248 | return UnsafeLinkedList.Contains(linkedList.GetInnerCollection(), item); 249 | } 250 | 251 | public static bool Remove(this NativeLinkedList linkedList, T item) 252 | where T : unmanaged, IEquatable 253 | { 254 | return UnsafeLinkedList.Remove(linkedList.GetInnerCollection(), item); 255 | } 256 | 257 | public static NativeLinkedList.Node Find(this NativeLinkedList linkedList, T item) 258 | where T : unmanaged, IEquatable 259 | { 260 | var node = UnsafeLinkedList.FindNode(linkedList.GetInnerCollection(), item); 261 | return new NativeLinkedList.Node(node); 262 | } 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/NativeList.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Runtime.CompilerServices; 30 | using UnsafeCollections.Collections.Unsafe; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native 34 | { 35 | [DebuggerDisplay("Count = {Count}")] 36 | [DebuggerTypeProxy(typeof(NativeCollectionDebugView<>))] 37 | public unsafe struct NativeList : INativeCollection, INativeReadOnlyCollection where T : unmanaged 38 | { 39 | private UnsafeList* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Count 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeList.GetCount(m_inner); 55 | } 56 | } 57 | public int Capacity 58 | { 59 | get 60 | { 61 | if (m_inner == null) 62 | throw new NullReferenceException(); 63 | return UnsafeList.GetCapacity(m_inner); 64 | } 65 | } 66 | public bool IsFixedSize 67 | { 68 | get 69 | { 70 | if (m_inner == null) 71 | throw new NullReferenceException(); 72 | return UnsafeList.IsFixedSize(m_inner); 73 | } 74 | } 75 | 76 | bool ICollection.IsReadOnly => false; 77 | 78 | public T this[int index] 79 | { 80 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 81 | get 82 | { 83 | return UnsafeList.Get(m_inner, index); 84 | } 85 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 86 | set 87 | { 88 | UnsafeList.Set(m_inner, index, value); 89 | } 90 | } 91 | 92 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 93 | internal UnsafeList* GetInnerCollection() 94 | { 95 | return m_inner; 96 | } 97 | 98 | public NativeList(int capacity) 99 | { 100 | m_inner = UnsafeList.Allocate(capacity, false); 101 | } 102 | 103 | public NativeList(int capacity, bool fixedSize) 104 | { 105 | m_inner = UnsafeList.Allocate(capacity, fixedSize); 106 | } 107 | 108 | public int SetCapacity(int capacity) 109 | { 110 | UnsafeList.SetCapacity(m_inner, capacity); 111 | 112 | return Capacity; 113 | } 114 | 115 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 116 | public void Add(T item) 117 | { 118 | UnsafeList.Add(m_inner, item); 119 | } 120 | 121 | public void AddRange(ICollection items) 122 | { 123 | if (Capacity < Count + items.Count) 124 | SetCapacity(Count + items.Count); 125 | 126 | int index = Count; 127 | using (var enumerator = items.GetEnumerator()) 128 | { 129 | while (enumerator.MoveNext()) 130 | Add(enumerator.Current); 131 | } 132 | } 133 | 134 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 135 | public ref T GetRef(int index) 136 | { 137 | return ref UnsafeList.GetRef(m_inner, index); 138 | } 139 | 140 | public void RemoteAt(int index) 141 | { 142 | UnsafeList.RemoveAt(m_inner, index); 143 | } 144 | 145 | public void RemoveAtUnordered(int index) 146 | { 147 | UnsafeList.RemoveAtUnordered(m_inner, index); 148 | } 149 | 150 | public void Clear() 151 | { 152 | UnsafeList.Clear(m_inner); 153 | } 154 | 155 | public T[] ToArray() 156 | { 157 | if (Count == 0) 158 | return Array.Empty(); 159 | 160 | var arr = new T[Count]; 161 | 162 | CopyTo(arr, 0); 163 | 164 | return arr; 165 | } 166 | 167 | public void CopyTo(T[] array, int arrayIndex) 168 | { 169 | if (array == null) 170 | throw new ArgumentNullException(nameof(array)); 171 | 172 | if ((uint)arrayIndex > array.Length) 173 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 174 | 175 | if (array.Length - arrayIndex < Count) 176 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 177 | 178 | if (array.Length == 0) 179 | return; 180 | 181 | fixed (void* ptr = array) 182 | UnsafeList.CopyTo(m_inner, ptr, arrayIndex); 183 | } 184 | 185 | public NativeArray ToNativeArray() 186 | { 187 | if (Count == 0) 188 | return NativeArray.Empty(); 189 | 190 | var arr = new NativeArray(Count); 191 | UnsafeList.CopyTo(m_inner, UnsafeArray.GetBuffer(arr.GetInnerCollection()), 0); 192 | 193 | return arr; 194 | } 195 | 196 | public UnsafeList.Enumerator GetEnumerator() 197 | { 198 | return UnsafeList.GetEnumerator(m_inner); 199 | } 200 | IEnumerator IEnumerable.GetEnumerator() 201 | { 202 | return UnsafeList.GetEnumerator(m_inner); 203 | } 204 | IEnumerator IEnumerable.GetEnumerator() 205 | { 206 | return UnsafeList.GetEnumerator(m_inner); 207 | } 208 | 209 | bool ICollection.Contains(T item) 210 | { 211 | return IndexOfSlow(item) > -1; 212 | } 213 | 214 | bool ICollection.Remove(T item) 215 | { 216 | int removeIndex = IndexOfSlow(item); 217 | 218 | if (removeIndex > -1) 219 | { 220 | UnsafeList.RemoveAt(m_inner, removeIndex); 221 | return true; 222 | } 223 | 224 | return false; 225 | } 226 | 227 | private int IndexOfSlow(T item) 228 | { 229 | var comparer = EqualityComparer.Default; 230 | 231 | for (int i = 0; i < Count; i++) 232 | { 233 | if (comparer.Equals(this[i], item)) 234 | return i; 235 | } 236 | 237 | return -1; 238 | } 239 | 240 | #if UNITY 241 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 242 | #endif 243 | public void Dispose() 244 | { 245 | UnsafeList.Free(m_inner); 246 | m_inner = null; 247 | } 248 | } 249 | 250 | // Extension methods are used to add extra constraints to 251 | public unsafe static class NativeListExtensions 252 | { 253 | public static bool Contains(this NativeList list, T item) where T : unmanaged, IEquatable 254 | { 255 | return UnsafeList.Contains(list.GetInnerCollection(), item); 256 | } 257 | 258 | public static int IndexOf(this NativeList list, T item) where T : unmanaged, IEquatable 259 | { 260 | return UnsafeList.IndexOf(list.GetInnerCollection(), item); 261 | } 262 | 263 | public static int LastIndexOf(this NativeList list, T item) where T : unmanaged, IEquatable 264 | { 265 | return UnsafeList.LastIndexOf(list.GetInnerCollection(), item); 266 | } 267 | 268 | public static bool Remove(this NativeList list, T item) where T : unmanaged, IEquatable 269 | { 270 | return UnsafeList.Remove(list.GetInnerCollection(), item); 271 | } 272 | 273 | public static bool RemoveUnordered(this NativeList list, T item) where T : unmanaged, IEquatable 274 | { 275 | return UnsafeList.RemoveUnordered(list.GetInnerCollection(), item); 276 | } 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/NativeQueue.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Runtime.CompilerServices; 30 | using UnsafeCollections.Collections.Unsafe; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native 34 | { 35 | [DebuggerDisplay("Count = {Count}")] 36 | [DebuggerTypeProxy(typeof(NativeReadOnlyCollectionDebugView<>))] 37 | public unsafe struct NativeQueue : INativeReadOnlyCollection where T : unmanaged 38 | { 39 | private UnsafeQueue* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Count 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeQueue.GetCount(m_inner); 55 | } 56 | } 57 | public int Capacity 58 | { 59 | get 60 | { 61 | if (m_inner == null) 62 | throw new NullReferenceException(); 63 | return UnsafeQueue.GetCapacity(m_inner); 64 | } 65 | } 66 | public bool IsFixedSize 67 | { 68 | get 69 | { 70 | if (m_inner == null) 71 | throw new NullReferenceException(); 72 | return UnsafeQueue.IsFixedSize(m_inner); 73 | } 74 | } 75 | 76 | 77 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 78 | internal UnsafeQueue* GetInnerCollection() 79 | { 80 | return m_inner; 81 | } 82 | 83 | public NativeQueue(int capacity) 84 | { 85 | m_inner = UnsafeQueue.Allocate(capacity, false); 86 | } 87 | 88 | public NativeQueue(int capacity, bool fixedSize) 89 | { 90 | m_inner = UnsafeQueue.Allocate(capacity, fixedSize); 91 | } 92 | 93 | 94 | public void Clear() 95 | { 96 | UnsafeQueue.Clear(m_inner); 97 | } 98 | 99 | public void Enqueue(T item) 100 | { 101 | UnsafeQueue.Enqueue(m_inner, item); 102 | } 103 | 104 | public bool TryEnqueue(T item) 105 | { 106 | return UnsafeQueue.TryEnqueue(m_inner, item); 107 | } 108 | 109 | public T Dequeue() 110 | { 111 | return UnsafeQueue.Dequeue(m_inner); 112 | } 113 | 114 | public bool TryDequeue(out T result) 115 | { 116 | return UnsafeQueue.TryDequeue(m_inner, out result); 117 | } 118 | 119 | public T Peek() 120 | { 121 | return UnsafeQueue.Peek(m_inner); 122 | } 123 | 124 | public bool TryPeek(out T result) 125 | { 126 | return UnsafeQueue.TryPeek(m_inner, out result); 127 | } 128 | 129 | 130 | public T[] ToArray() 131 | { 132 | if (Count == 0) 133 | return Array.Empty(); 134 | 135 | var arr = new T[Count]; 136 | 137 | CopyTo(arr, 0); 138 | 139 | return arr; 140 | } 141 | 142 | public void CopyTo(T[] array, int arrayIndex) 143 | { 144 | if (array == null) 145 | throw new ArgumentNullException(nameof(array)); 146 | 147 | if ((uint)arrayIndex > array.Length) 148 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 149 | 150 | if (array.Length - arrayIndex < Count) 151 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 152 | 153 | if (array.Length == 0) 154 | return; 155 | 156 | fixed (void* ptr = array) 157 | UnsafeQueue.CopyTo(m_inner, ptr, arrayIndex); 158 | } 159 | 160 | public NativeArray ToNativeArray() 161 | { 162 | if (Count == 0) 163 | return NativeArray.Empty(); 164 | 165 | var arr = new NativeArray(Count); 166 | UnsafeQueue.CopyTo(m_inner, UnsafeArray.GetBuffer(arr.GetInnerCollection()), 0); 167 | 168 | return arr; 169 | } 170 | 171 | 172 | public UnsafeList.Enumerator GetEnumerator() 173 | { 174 | return UnsafeQueue.GetEnumerator(m_inner); 175 | } 176 | IEnumerator IEnumerable.GetEnumerator() 177 | { 178 | return UnsafeQueue.GetEnumerator(m_inner); 179 | } 180 | IEnumerator IEnumerable.GetEnumerator() 181 | { 182 | return UnsafeQueue.GetEnumerator(m_inner); 183 | } 184 | 185 | #if UNITY 186 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 187 | #endif 188 | public void Dispose() 189 | { 190 | UnsafeQueue.Free(m_inner); 191 | m_inner = null; 192 | } 193 | } 194 | 195 | //Extension methods are used to add extra constraints to 196 | public unsafe static class NativeQueueExtensions 197 | { 198 | public static bool Contains(this NativeQueue queue, T item) where T : unmanaged, IEquatable 199 | { 200 | return UnsafeQueue.Contains(queue.GetInnerCollection(), item); 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/NativeRingBuffer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Runtime.CompilerServices; 30 | using UnsafeCollections.Collections.Unsafe; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native 34 | { 35 | [DebuggerDisplay("Count = {Count}")] 36 | [DebuggerTypeProxy(typeof(NativeReadOnlyCollectionDebugView<>))] 37 | public unsafe struct NativeRingBuffer : INativeReadOnlyCollection where T : unmanaged 38 | { 39 | private UnsafeRingBuffer* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Count 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeRingBuffer.GetCount(m_inner); 55 | } 56 | } 57 | public int Capacity 58 | { 59 | get 60 | { 61 | if (m_inner == null) 62 | throw new NullReferenceException(); 63 | return UnsafeRingBuffer.GetCapacity(m_inner); 64 | } 65 | } 66 | public bool IsFull 67 | { 68 | get 69 | { 70 | if (m_inner == null) 71 | throw new NullReferenceException(); 72 | return UnsafeRingBuffer.IsFull(m_inner); 73 | } 74 | } 75 | 76 | public T this[int index] 77 | { 78 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 79 | get 80 | { 81 | return UnsafeRingBuffer.Get(m_inner, index); 82 | } 83 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 84 | set 85 | { 86 | UnsafeRingBuffer.Set(m_inner, index, value); 87 | } 88 | } 89 | 90 | 91 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 92 | internal UnsafeRingBuffer* GetInnerCollection() 93 | { 94 | return m_inner; 95 | } 96 | 97 | public NativeRingBuffer(int capacity) 98 | { 99 | m_inner = UnsafeRingBuffer.Allocate(capacity); 100 | } 101 | 102 | public NativeRingBuffer(int capacity, bool overwrite) 103 | { 104 | m_inner = UnsafeRingBuffer.Allocate(capacity, overwrite); 105 | } 106 | 107 | 108 | public void Clear() 109 | { 110 | UnsafeRingBuffer.Clear(m_inner); 111 | } 112 | 113 | public ref T GetRef(int index) 114 | { 115 | return ref UnsafeRingBuffer.GetRef(m_inner, index); 116 | } 117 | 118 | 119 | public bool Push(T item) 120 | { 121 | return UnsafeRingBuffer.Push(m_inner, item); 122 | } 123 | 124 | public bool Pop(out T value) 125 | { 126 | return UnsafeRingBuffer.Pop(m_inner, out value); 127 | } 128 | 129 | public bool Peek(out T value) 130 | { 131 | return UnsafeRingBuffer.Peek(m_inner, out value); 132 | } 133 | 134 | 135 | public void CopyTo(T[] array, int arrayIndex) 136 | { 137 | if (array == null) 138 | throw new ArgumentNullException(nameof(array)); 139 | 140 | if ((uint)arrayIndex > array.Length) 141 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 142 | 143 | if (array.Length - arrayIndex < Count) 144 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 145 | 146 | if (array.Length == 0) 147 | return; 148 | 149 | fixed (void* ptr = array) 150 | UnsafeRingBuffer.CopyTo(m_inner, ptr, arrayIndex); 151 | } 152 | 153 | public T[] ToArray() 154 | { 155 | if (Count == 0) 156 | return Array.Empty(); 157 | 158 | var arr = new T[Count]; 159 | 160 | CopyTo(arr, 0); 161 | 162 | return arr; 163 | } 164 | 165 | public NativeArray ToNativeArray() 166 | { 167 | if (Count == 0) 168 | return NativeArray.Empty(); 169 | 170 | var arr = new NativeArray(Count); 171 | UnsafeRingBuffer.CopyTo(m_inner, UnsafeArray.GetBuffer(arr.GetInnerCollection()), 0); 172 | 173 | return arr; 174 | } 175 | 176 | public UnsafeList.Enumerator GetEnumerator() 177 | { 178 | return UnsafeRingBuffer.GetEnumerator(m_inner); 179 | } 180 | IEnumerator IEnumerable.GetEnumerator() 181 | { 182 | return UnsafeRingBuffer.GetEnumerator(m_inner); 183 | } 184 | IEnumerator IEnumerable.GetEnumerator() 185 | { 186 | return UnsafeRingBuffer.GetEnumerator(m_inner); 187 | } 188 | 189 | #if UNITY 190 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 191 | #endif 192 | public void Dispose() 193 | { 194 | UnsafeRingBuffer.Free(m_inner); 195 | m_inner = null; 196 | } 197 | } 198 | 199 | //Extension methods are used to add extra constraints to 200 | public unsafe static class NativeRingBufferExtensions 201 | { 202 | public static bool Contains(this NativeRingBuffer ringBuffer, T item) where T : unmanaged, IEquatable 203 | { 204 | return UnsafeRingBuffer.Contains(ringBuffer.GetInnerCollection(), item); 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/NativeSortedSet.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Runtime.CompilerServices; 30 | using UnsafeCollections.Collections.Unsafe; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native 34 | { 35 | [DebuggerDisplay("Count = {Count}")] 36 | [DebuggerTypeProxy(typeof(NativeReadOnlyCollectionDebugView<>))] 37 | public unsafe struct NativeSortedSet : INativeReadOnlyCollection, INativeCollection 38 | where T : unmanaged, IComparable 39 | { 40 | private UnsafeSortedSet* m_inner; 41 | 42 | public bool IsCreated 43 | { 44 | get 45 | { 46 | return m_inner != null; 47 | } 48 | } 49 | public int Count 50 | { 51 | get 52 | { 53 | if (m_inner == null) 54 | throw new NullReferenceException(); 55 | return UnsafeSortedSet.GetCount(m_inner); 56 | } 57 | } 58 | public int Capacity 59 | { 60 | get 61 | { 62 | if (m_inner == null) 63 | throw new NullReferenceException(); 64 | return UnsafeSortedSet.GetCapacity(m_inner); 65 | } 66 | } 67 | public bool IsFixedSize 68 | { 69 | get 70 | { 71 | if (m_inner == null) 72 | throw new NullReferenceException(); 73 | return UnsafeSortedSet.IsFixedSize(m_inner); 74 | } 75 | } 76 | 77 | public bool IsReadOnly => false; 78 | 79 | public NativeSortedSet(int capacity) 80 | { 81 | m_inner = UnsafeSortedSet.Allocate(capacity, false); 82 | } 83 | 84 | public NativeSortedSet(int capacity, bool fixedSize) 85 | { 86 | m_inner = UnsafeSortedSet.Allocate(capacity, fixedSize); 87 | } 88 | 89 | 90 | public void Add(T item) 91 | { 92 | UnsafeSortedSet.Add(m_inner, item); 93 | } 94 | 95 | public void Clear() 96 | { 97 | UnsafeSortedSet.Clear(m_inner); 98 | } 99 | 100 | public bool Contains(T item) 101 | { 102 | return UnsafeSortedSet.Contains(m_inner, item); 103 | } 104 | 105 | public bool Remove(T item) 106 | { 107 | return UnsafeSortedSet.Remove(m_inner, item); 108 | } 109 | 110 | 111 | public T[] ToArray() 112 | { 113 | if (Count == 0) 114 | return Array.Empty(); 115 | 116 | var arr = new T[Count]; 117 | 118 | CopyTo(arr, 0); 119 | 120 | return arr; 121 | } 122 | 123 | public void CopyTo(T[] array, int arrayIndex) 124 | { 125 | if (array == null) 126 | throw new ArgumentNullException(nameof(array)); 127 | 128 | if ((uint)arrayIndex > array.Length) 129 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 130 | 131 | if (array.Length - arrayIndex < Count) 132 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 133 | 134 | if (array.Length == 0) 135 | return; 136 | 137 | fixed (void* ptr = array) 138 | UnsafeSortedSet.CopyTo(m_inner, ptr, arrayIndex); 139 | } 140 | 141 | public NativeArray ToNativeArray() 142 | { 143 | if (Count == 0) 144 | return NativeArray.Empty(); 145 | 146 | var arr = new NativeArray(Count); 147 | UnsafeSortedSet.CopyTo(m_inner, UnsafeArray.GetBuffer(arr.GetInnerCollection()), 0); 148 | 149 | return arr; 150 | } 151 | 152 | 153 | public UnsafeSortedSet.Enumerator GetEnumerator() 154 | { 155 | return UnsafeSortedSet.GetEnumerator(m_inner); 156 | } 157 | IEnumerator IEnumerable.GetEnumerator() 158 | { 159 | return UnsafeSortedSet.GetEnumerator(m_inner); 160 | } 161 | IEnumerator IEnumerable.GetEnumerator() 162 | { 163 | return UnsafeSortedSet.GetEnumerator(m_inner); 164 | } 165 | 166 | #if UNITY 167 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 168 | #endif 169 | public void Dispose() 170 | { 171 | UnsafeSortedSet.Free(m_inner); 172 | m_inner = null; 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Native/NativeStack.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Runtime.CompilerServices; 30 | using UnsafeCollections.Collections.Unsafe; 31 | using UnsafeCollections.Debug.TypeProxies; 32 | 33 | namespace UnsafeCollections.Collections.Native 34 | { 35 | [DebuggerDisplay("Count = {Count}")] 36 | [DebuggerTypeProxy(typeof(NativeReadOnlyCollectionDebugView<>))] 37 | public unsafe struct NativeStack : INativeReadOnlyCollection where T : unmanaged 38 | { 39 | private UnsafeStack* m_inner; 40 | 41 | public bool IsCreated 42 | { 43 | get 44 | { 45 | return m_inner != null; 46 | } 47 | } 48 | public int Count 49 | { 50 | get 51 | { 52 | if (m_inner == null) 53 | throw new NullReferenceException(); 54 | return UnsafeStack.GetCount(m_inner); 55 | } 56 | } 57 | public int Capacity 58 | { 59 | get 60 | { 61 | if (m_inner == null) 62 | throw new NullReferenceException(); 63 | return UnsafeStack.GetCapacity(m_inner); 64 | } 65 | } 66 | public bool IsFixedSize 67 | { 68 | get 69 | { 70 | if (m_inner == null) 71 | throw new NullReferenceException(); 72 | return UnsafeStack.IsFixedSize(m_inner); 73 | } 74 | } 75 | 76 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 77 | internal UnsafeStack* GetInnerCollection() 78 | { 79 | return m_inner; 80 | } 81 | 82 | public NativeStack(int capacity) 83 | { 84 | m_inner = UnsafeStack.Allocate(capacity); 85 | } 86 | 87 | public NativeStack(int capacity, bool fixedSize) 88 | { 89 | m_inner = UnsafeStack.Allocate(capacity, fixedSize); 90 | } 91 | 92 | 93 | public T Peek() 94 | { 95 | return UnsafeStack.Peek(m_inner); 96 | } 97 | 98 | public bool TryPeek(out T item) 99 | { 100 | return UnsafeStack.TryPeek(m_inner, out item); 101 | } 102 | 103 | public T Pop() 104 | { 105 | return UnsafeStack.Pop(m_inner); 106 | } 107 | 108 | public bool TryPop(out T item) 109 | { 110 | return UnsafeStack.TryPop(m_inner, out item); 111 | } 112 | 113 | public void Push(T item) 114 | { 115 | UnsafeStack.Push(m_inner, item); 116 | } 117 | 118 | public bool TryPush(T item) 119 | { 120 | return UnsafeStack.TryPush(m_inner, item); 121 | } 122 | 123 | 124 | public void CopyTo(T[] array, int arrayIndex) 125 | { 126 | if (array == null) 127 | throw new ArgumentNullException(nameof(array)); 128 | 129 | if ((uint)arrayIndex > array.Length) 130 | throw new ArgumentOutOfRangeException(nameof(arrayIndex)); 131 | 132 | if (array.Length - arrayIndex < Count) 133 | throw new ArgumentException("Insufficient space in the target location to copy the information."); 134 | 135 | if (array.Length == 0) 136 | return; 137 | 138 | fixed (void* ptr = array) 139 | UnsafeStack.CopyTo(m_inner, ptr, arrayIndex); 140 | } 141 | 142 | public T[] ToArray() 143 | { 144 | if (Count == 0) 145 | return Array.Empty(); 146 | 147 | var arr = new T[Count]; 148 | 149 | CopyTo(arr, 0); 150 | 151 | return arr; 152 | } 153 | 154 | public NativeArray ToNativeArray() 155 | { 156 | if (Count == 0) 157 | return NativeArray.Empty(); 158 | 159 | var arr = new NativeArray(Count); 160 | UnsafeStack.CopyTo(m_inner, UnsafeArray.GetBuffer(arr.GetInnerCollection()), 0); 161 | 162 | return arr; 163 | } 164 | 165 | public UnsafeStack.Enumerator GetEnumerator() 166 | { 167 | return UnsafeStack.GetEnumerator(m_inner); 168 | } 169 | IEnumerator IEnumerable.GetEnumerator() 170 | { 171 | return UnsafeStack.GetEnumerator(m_inner); 172 | } 173 | IEnumerator IEnumerable.GetEnumerator() 174 | { 175 | return UnsafeStack.GetEnumerator(m_inner); 176 | } 177 | 178 | #if UNITY 179 | [Unity.Collections.LowLevel.Unsafe.WriteAccessRequired] 180 | #endif 181 | public void Dispose() 182 | { 183 | UnsafeStack.Free(m_inner); 184 | m_inner = null; 185 | } 186 | } 187 | 188 | //Extension methods are used to add extra constraints to 189 | public unsafe static class NativeStackExtensions 190 | { 191 | public static bool Contains(this NativeStack stack, T item) where T : unmanaged, IEquatable 192 | { 193 | return UnsafeStack.Contains(stack.GetInnerCollection(), item); 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Unsafe/Concurrent/HeadAndTail.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System.Diagnostics; 26 | using System.Runtime.InteropServices; 27 | 28 | namespace UnsafeCollections.Collections.Unsafe.Concurrent 29 | { 30 | // Used by all ConcurrentQueue implementations 31 | [StructLayout(LayoutKind.Explicit, Size = 3 * CACHE_LINE_SIZE)] 32 | [DebuggerDisplay("Head = {Head}, Tail = {Tail}")] 33 | internal struct HeadAndTail 34 | { 35 | private const int CACHE_LINE_SIZE = 64; 36 | 37 | [FieldOffset(1 * CACHE_LINE_SIZE)] 38 | public int Head; 39 | 40 | [FieldOffset(2 * CACHE_LINE_SIZE)] 41 | public int Tail; 42 | } 43 | 44 | // This struct is only used to get the size in memory 45 | [StructLayout(LayoutKind.Sequential)] 46 | internal struct QueueSlot 47 | { 48 | #pragma warning disable IDE0044 49 | T Item; 50 | int SequenceNumber; 51 | #pragma warning restore IDE0044 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Unsafe/IUnsafeIterator.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Fredrik Holmstrom 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System.Collections.Generic; 26 | 27 | namespace UnsafeCollections.Collections.Unsafe 28 | { 29 | public interface IUnsafeEnumerator : IEnumerable, IEnumerator where T : struct 30 | { 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Unsafe/MapInsertionBehaviour.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | namespace UnsafeCollections.Collections.Unsafe 26 | { 27 | internal enum MapInsertionBehaviour : byte 28 | { 29 | None = 0, 30 | Overwrite = 1, 31 | ThrowIfExists = 2 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Unsafe/UnsafeLock.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Threading; 27 | 28 | namespace UnsafeCollections.Collections.Unsafe 29 | { 30 | internal class UnsafeLockException : Exception 31 | { 32 | public UnsafeLockException() 33 | { } 34 | 35 | public UnsafeLockException(string message) : base(message) 36 | { } 37 | } 38 | 39 | internal struct UnsafeLock 40 | { 41 | const int Locked = 1; 42 | const int Unlocked = 0; 43 | 44 | volatile int _lock; 45 | 46 | public void Lock() 47 | { 48 | while (Interlocked.CompareExchange(ref _lock, Locked, Unlocked) != Unlocked) 49 | { 50 | Thread.SpinWait(1); 51 | } 52 | } 53 | 54 | public void Unlock() 55 | { 56 | if (Interlocked.CompareExchange(ref _lock, Unlocked, Locked) != Locked) 57 | { 58 | throw new UnsafeLockException("Trying to unlock a lock that was not locked."); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /UnsafeCollections/Collections/Unsafe/UnsafeSortedSet.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Fredrik Holmstrom 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Runtime.CompilerServices; 29 | using UnsafeCollections.Debug; 30 | 31 | namespace UnsafeCollections.Collections.Unsafe 32 | { 33 | public unsafe struct UnsafeSortedSet 34 | { 35 | UnsafeOrderedCollection _collection; 36 | IntPtr _typeHandle; 37 | 38 | public static UnsafeSortedSet* Allocate(int capacity, bool fixedSize = false) 39 | where T : unmanaged, IComparable 40 | { 41 | var valStride = sizeof(T); 42 | var entryStride = sizeof(UnsafeOrderedCollection.Entry); 43 | var valAlignment = Memory.GetAlignment(valStride); 44 | 45 | // the alignment for entry/key/val, we can't have less than ENTRY_ALIGNMENT 46 | // bytes alignment because entries are 12 bytes with 3 x 32 bit integers 47 | var alignment = Math.Max(UnsafeOrderedCollection.Entry.ALIGNMENT, valAlignment); 48 | 49 | // calculate strides for all elements 50 | valStride = Memory.RoundToAlignment(valStride, alignment); 51 | entryStride = Memory.RoundToAlignment(entryStride, alignment); 52 | 53 | // dictionary ptr 54 | UnsafeSortedSet* set; 55 | 56 | if (fixedSize) 57 | { 58 | var sizeOfHeader = Memory.RoundToAlignment(sizeof(UnsafeSortedSet), alignment); 59 | var sizeofEntriesBuffer = (entryStride + valStride) * capacity; 60 | 61 | // allocate memory 62 | var ptr = Memory.MallocAndZero(sizeOfHeader + sizeofEntriesBuffer, alignment); 63 | 64 | // start of memory is the set itself 65 | set = (UnsafeSortedSet*)ptr; 66 | 67 | // initialize fixed buffer 68 | UnsafeBuffer.InitFixed(&set->_collection.Entries, (byte*)ptr + sizeOfHeader, capacity, entryStride + valStride); 69 | } 70 | else 71 | { 72 | // allocate set separately 73 | set = Memory.MallocAndZero(); 74 | 75 | // init dynamic buffer 76 | UnsafeBuffer.InitDynamic(&set->_collection.Entries, capacity, entryStride + valStride); 77 | } 78 | 79 | set->_collection.FreeCount = 0; 80 | set->_collection.UsedCount = 0; 81 | set->_collection.KeyOffset = entryStride; 82 | set->_typeHandle = typeof(T).TypeHandle.Value; 83 | 84 | return set; 85 | } 86 | 87 | public static void Free(UnsafeSortedSet* set) 88 | { 89 | if (set == null) 90 | return; 91 | 92 | if (set->_collection.Entries.Dynamic == 1) 93 | { 94 | UnsafeBuffer.Free(&set->_collection.Entries); 95 | } 96 | 97 | // clear memory 98 | *set = default; 99 | 100 | // free it 101 | Memory.Free(set); 102 | } 103 | 104 | public static int GetCount(UnsafeSortedSet* set) 105 | { 106 | UDebug.Assert(set != null); 107 | 108 | return UnsafeOrderedCollection.GetCount(&set->_collection); 109 | } 110 | 111 | public static int GetCapacity(UnsafeSortedSet* set) 112 | { 113 | UDebug.Assert(set != null); 114 | 115 | return set->_collection.Entries.Length; 116 | } 117 | 118 | public static bool IsFixedSize(UnsafeSortedSet* set) 119 | { 120 | UDebug.Assert(set != null); 121 | 122 | return set->_collection.Entries.Dynamic == 0; 123 | } 124 | 125 | public static void Add(UnsafeSortedSet* set, T item) 126 | where T : unmanaged, IComparable 127 | { 128 | UDebug.Assert(set != null); 129 | UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); 130 | 131 | UnsafeOrderedCollection.Insert(&set->_collection, item); 132 | } 133 | 134 | public static bool Remove(UnsafeSortedSet* set, T item) 135 | where T : unmanaged, IComparable 136 | { 137 | UDebug.Assert(set != null); 138 | UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); 139 | 140 | return UnsafeOrderedCollection.Remove(&set->_collection, item); 141 | } 142 | 143 | public static bool Contains(UnsafeSortedSet* set, T item) 144 | where T : unmanaged, IComparable 145 | { 146 | UDebug.Assert(set != null); 147 | UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); 148 | 149 | return UnsafeOrderedCollection.Find(&set->_collection, item) != null; 150 | } 151 | 152 | public static void Clear(UnsafeSortedSet* set) 153 | { 154 | UDebug.Assert(set != null); 155 | 156 | UnsafeOrderedCollection.Clear(&set->_collection); 157 | } 158 | 159 | public static void CopyTo(UnsafeSortedSet* set, void* destination, int destinationIndex) 160 | where T : unmanaged 161 | { 162 | if (destination == null) 163 | throw new ArgumentNullException(nameof(destination)); 164 | 165 | if (destinationIndex < 0) 166 | throw new ArgumentOutOfRangeException(ThrowHelper.ArgumentOutOfRange_Index); 167 | UDebug.Assert(set != null); 168 | UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); 169 | 170 | var enumerator = GetEnumerator(set); 171 | var dest = (T*)destination; 172 | 173 | int i = 0; 174 | while (enumerator.MoveNext()) 175 | { 176 | dest[destinationIndex + i] = enumerator.Current; 177 | i++; 178 | } 179 | } 180 | 181 | public static Enumerator GetEnumerator(UnsafeSortedSet* set) where T : unmanaged 182 | { 183 | UDebug.Assert(set != null); 184 | UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); 185 | 186 | return new Enumerator(set); 187 | } 188 | 189 | public unsafe struct Enumerator : IUnsafeEnumerator where T : unmanaged 190 | { 191 | readonly int _keyOffset; 192 | UnsafeOrderedCollection.Enumerator _iterator; 193 | 194 | public Enumerator(UnsafeSortedSet* set) 195 | { 196 | _keyOffset = set->_collection.KeyOffset; 197 | _iterator = new UnsafeOrderedCollection.Enumerator(&set->_collection); 198 | } 199 | 200 | public T Current 201 | { 202 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 203 | get 204 | { 205 | UDebug.Assert(_iterator.Current != null); 206 | return *(T*)((byte*)_iterator.Current + _keyOffset); 207 | } 208 | } 209 | 210 | object IEnumerator.Current 211 | { 212 | get { return Current; } 213 | } 214 | 215 | public bool MoveNext() 216 | { 217 | return _iterator.MoveNext(); 218 | } 219 | 220 | public void Reset() 221 | { 222 | _iterator.Reset(); 223 | } 224 | 225 | public void Dispose() 226 | { } 227 | 228 | public Enumerator GetEnumerator() 229 | { 230 | return this; 231 | } 232 | IEnumerator IEnumerable.GetEnumerator() 233 | { 234 | return this; 235 | } 236 | IEnumerator IEnumerable.GetEnumerator() 237 | { 238 | return this; 239 | } 240 | } 241 | } 242 | } -------------------------------------------------------------------------------- /UnsafeCollections/Debug/AssertException.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | 27 | namespace UnsafeCollections 28 | { 29 | internal sealed class AssertException : Exception 30 | { 31 | public AssertException() 32 | { } 33 | 34 | public AssertException(string message) : base(message) 35 | { } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /UnsafeCollections/Debug/ThrowHelper.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | namespace UnsafeCollections.Debug 26 | { 27 | internal static class ThrowHelper 28 | { 29 | internal const string @Arg_ArrayLengthsDiffer = "Array lengths must be the same."; 30 | internal const string @Arg_ArrayPlusOffTooSmall = "Destination array is not long enough to copy all the items in the collection. Check array index and length."; 31 | 32 | internal const string @Arg_AddingDuplicateWithKey = "An item with the same key has already been added. Key: {0}"; 33 | internal const string @Arg_KeyNotFoundWithKey = "Arg_KeyNotFoundWithKey"; 34 | 35 | internal const string @ArgumentOutOfRange_Index = "Index was out of range. Must be non-negative and less than the size of the collection."; 36 | internal const string @ArgumentOutOfRange_MustBeNonNegInt32 = "Value must be non-negative and less than or equal to Int32.MaxValue."; 37 | internal const string @ArgumentOutOfRange_MustBeNonNegNum = "{0} must be non-negative."; 38 | internal const string @ArgumentOutOfRange_MustBePositive = "{0} must be greater than zero."; 39 | internal const string @ArgumentOutOfRange_NeedNonNegNum = "Non-negative number required."; 40 | 41 | internal const string @InvalidOperation_EnumOpCantHappen = "Enumeration has either not started or has already finished."; 42 | internal const string @InvalidOperation_EnumFailedVersion = "Collection was modified; enumeration operation may not execute."; 43 | 44 | internal const string @InvalidOperation_CollectionFull = "Fixed size collection is full."; 45 | internal const string @InvalidOperation_EmptyQueue = "Queue empty."; 46 | internal const string @InvalidOperation_EmptyStack = "Stack empty."; 47 | internal const string @InvalidOperation_EmptyHeap = "Heap empty."; 48 | internal const string @InvalidOperation_EmptyLinkedList = "The LinkedList is empty."; 49 | 50 | internal const string @Arg_BitSetLengthsDiffer = "BitSet lengths must be the same."; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /UnsafeCollections/Debug/TypeProxies/NativeArrayDebugView.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Diagnostics; 27 | using UnsafeCollections.Collections.Native; 28 | 29 | namespace UnsafeCollections.Debug.TypeProxies 30 | { 31 | internal struct NativeArrayDebugView where T : unmanaged 32 | { 33 | private readonly INativeArray m_array; 34 | 35 | public NativeArrayDebugView(INativeArray array) 36 | { 37 | if (array == null || !array.IsCreated) 38 | throw new ArgumentNullException(nameof(array)); 39 | 40 | m_array = array; 41 | } 42 | 43 | [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] 44 | public T[] Items => m_array.ToArray(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /UnsafeCollections/Debug/TypeProxies/NativeBitSetDebugView.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Diagnostics; 27 | using UnsafeCollections.Collections.Native; 28 | 29 | namespace UnsafeCollections.Debug.TypeProxies 30 | { 31 | internal struct NativeBitSetDebugView 32 | { 33 | private readonly NativeBitSet m_bitset; 34 | 35 | public NativeBitSetDebugView(NativeBitSet bitset) 36 | { 37 | if (!bitset.IsCreated) 38 | throw new ArgumentNullException(nameof(bitset)); 39 | 40 | m_bitset = bitset; 41 | } 42 | 43 | [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] 44 | public byte[] Items => m_bitset.ToArray(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /UnsafeCollections/Debug/TypeProxies/NativeCollectionDebugView.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Diagnostics; 27 | using UnsafeCollections.Collections.Native; 28 | 29 | namespace UnsafeCollections.Debug.TypeProxies 30 | { 31 | internal struct NativeCollectionDebugView where T : unmanaged 32 | { 33 | private readonly INativeCollection m_collection; 34 | 35 | public NativeCollectionDebugView(INativeCollection collection) 36 | { 37 | if (collection == null || !collection.IsCreated) 38 | throw new ArgumentNullException(nameof(collection)); 39 | 40 | m_collection = collection; 41 | } 42 | 43 | [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] 44 | public T[] Items 45 | { 46 | get 47 | { 48 | var arr = new T[m_collection.Count]; 49 | m_collection.CopyTo(arr, 0); 50 | 51 | return arr; 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /UnsafeCollections/Debug/TypeProxies/NativeDictionaryDebugView.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Diagnostics; 28 | using UnsafeCollections.Collections.Native; 29 | 30 | namespace UnsafeCollections.Debug.TypeProxies 31 | { 32 | internal struct NativeDictionaryDebugView 33 | where K : unmanaged 34 | where V : unmanaged 35 | { 36 | private readonly INativeDictionary _dictionary; 37 | 38 | public NativeDictionaryDebugView(INativeDictionary dictionary) 39 | { 40 | if (dictionary == null || !dictionary.IsCreated) 41 | throw new ArgumentNullException(nameof(dictionary)); 42 | _dictionary = dictionary; 43 | } 44 | 45 | [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] 46 | public KeyValuePair[] Items 47 | { 48 | get 49 | { 50 | var items = new KeyValuePair[_dictionary.Count]; 51 | _dictionary.CopyTo(items, 0); 52 | 53 | return items; 54 | } 55 | } 56 | } 57 | 58 | internal struct NativeDictionaryKeyCollectionDebugView 59 | where K : unmanaged 60 | where V : unmanaged 61 | { 62 | private readonly ICollection _collection; 63 | 64 | public NativeDictionaryKeyCollectionDebugView(ICollection collection) 65 | { 66 | _collection = collection ?? throw new ArgumentNullException(nameof(collection)); 67 | } 68 | 69 | [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] 70 | public K[] Items 71 | { 72 | get 73 | { 74 | K[] items = new K[_collection.Count]; 75 | _collection.CopyTo(items, 0); 76 | return items; 77 | } 78 | } 79 | } 80 | 81 | internal struct NativeDictionaryValueCollectionDebugView 82 | where K : unmanaged 83 | where V : unmanaged 84 | { 85 | private readonly ICollection _collection; 86 | 87 | public NativeDictionaryValueCollectionDebugView(ICollection collection) 88 | { 89 | _collection = collection ?? throw new ArgumentNullException(nameof(collection)); 90 | } 91 | 92 | [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] 93 | public V[] Items 94 | { 95 | get 96 | { 97 | V[] items = new V[_collection.Count]; 98 | _collection.CopyTo(items, 0); 99 | return items; 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /UnsafeCollections/Debug/TypeProxies/NativeReadOnlyCollectionDebugView.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Diagnostics; 27 | using UnsafeCollections.Collections.Native; 28 | 29 | namespace UnsafeCollections.Debug.TypeProxies 30 | { 31 | internal struct NativeReadOnlyCollectionDebugView where T : unmanaged 32 | { 33 | private readonly INativeReadOnlyCollection m_collection; 34 | 35 | public NativeReadOnlyCollectionDebugView(INativeReadOnlyCollection collection) 36 | { 37 | if (collection == null || !collection.IsCreated) 38 | throw new ArgumentNullException(nameof(collection)); 39 | 40 | m_collection = collection; 41 | } 42 | 43 | [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] 44 | public T[] Items 45 | { 46 | get 47 | { 48 | var arr = new T[m_collection.Count]; 49 | m_collection.CopyTo(arr, 0); 50 | 51 | return arr; 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /UnsafeCollections/Debug/UDebug.cs: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) Dennis Corvers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | namespace UnsafeCollections 26 | { 27 | internal static class UDebug 28 | { 29 | [System.Diagnostics.Conditional("DEBUG")] 30 | [System.Diagnostics.DebuggerStepThrough] 31 | public static void Assert(bool condition) 32 | { 33 | if (!condition) 34 | throw new AssertException(); 35 | } 36 | 37 | [System.Diagnostics.Conditional("DEBUG")] 38 | [System.Diagnostics.DebuggerStepThrough] 39 | public static void Assert(bool condition, string message) 40 | { 41 | if (!condition) 42 | throw new AssertException(message); 43 | } 44 | 45 | [System.Diagnostics.Conditional("DEBUG")] 46 | [System.Diagnostics.DebuggerStepThrough] 47 | public static void Assert(bool condition, string format, params object[] args) 48 | { 49 | Assert(condition, string.Format(format, args)); 50 | } 51 | 52 | [System.Diagnostics.Conditional("DEBUG")] 53 | [System.Diagnostics.DebuggerStepThrough] 54 | public static void Assert(bool condition, string message, string format, params object[] args) 55 | { 56 | Assert(condition, message + " : " + string.Format(format, args)); 57 | } 58 | 59 | [System.Diagnostics.Conditional("DEBUG")] 60 | [System.Diagnostics.DebuggerStepThrough] 61 | public static void Fail(string message) 62 | { 63 | throw new AssertException(message); 64 | } 65 | 66 | [System.Diagnostics.Conditional("DEBUG")] 67 | [System.Diagnostics.DebuggerStepThrough] 68 | public static void Fail(string format, params object[] args) 69 | { 70 | throw new AssertException(string.Format(format, args)); 71 | } 72 | 73 | public static void Always(bool condition) 74 | { 75 | if (!condition) 76 | throw new AssertException(); 77 | } 78 | 79 | public static void Always(bool condition, string error) 80 | { 81 | if (!condition) 82 | throw new AssertException(error); 83 | } 84 | 85 | public static void Always(bool condition, string format, params object[] args) 86 | { 87 | if (!condition) 88 | throw new AssertException(string.Format(format, args)); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /UnsafeCollections/UnsafeCollections.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 7.3 6 | Debug;Release;Unity 7 | 8 | 9 | 10 | true 11 | 12 | 13 | 14 | true 15 | TRACE;UNITY 16 | true 17 | 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | C:\Program Files\Unity\Editor\Data\Managed\UnityEngine.dll 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Native/NativeArrayTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using UnsafeCollections.Collections.Native; 6 | using UnsafeCollections.Debug.TypeProxies; 7 | 8 | namespace UnsafeCollectionsTests.Native 9 | { 10 | public unsafe class NativeArrayTests 11 | { 12 | //[Test] 13 | public void Test() 14 | { 15 | NativeArray arr = new NativeArray(10); 16 | 17 | for (int i = 0; i < 10; i++) 18 | { 19 | arr[i] = (float)(i * i) / 3; 20 | } 21 | 22 | } 23 | 24 | [Test] 25 | public void ConstructorTest() 26 | { 27 | NativeArray arr = new NativeArray(10); 28 | 29 | Assert.IsTrue(arr.IsCreated); 30 | 31 | arr.Dispose(); 32 | 33 | Assert.IsFalse(arr.IsCreated); 34 | } 35 | 36 | [Test] 37 | public void IndexTest() 38 | { 39 | NativeArray arr = new NativeArray(10); 40 | 41 | for (int i = 0; i < 10; i++) 42 | arr[i] = i; 43 | 44 | for (int i = 0; i < 10; i++) 45 | Assert.AreEqual(i, arr[i]); 46 | 47 | arr.Dispose(); 48 | } 49 | 50 | [Test] 51 | public void IteratorTest() 52 | { 53 | NativeArray arr = new NativeArray(10); 54 | 55 | for (int i = 0; i < 10; i++) 56 | arr[i] = i; 57 | 58 | int c = 0; 59 | foreach (int i in arr) 60 | Assert.AreEqual(c++, i); 61 | 62 | arr.Dispose(); 63 | } 64 | 65 | [Test] 66 | public void FromArrayTest() 67 | { 68 | var intArr = new int[10]; 69 | 70 | for (int i = 0; i < 10; i++) 71 | intArr[i] = i; 72 | 73 | NativeArray arr = new NativeArray(intArr); 74 | 75 | Assert.AreEqual(intArr.Length, arr.Length); 76 | 77 | for (int i = 0; i < 10; i++) 78 | Assert.AreEqual(i, arr[i]); 79 | 80 | arr.Dispose(); 81 | } 82 | 83 | [Test] 84 | public void ToArrayTest() 85 | { 86 | NativeArray arr = new NativeArray(10); 87 | 88 | for (int i = 0; i < 10; i++) 89 | arr[i] = i; 90 | 91 | var intArr = arr.ToArray(); 92 | 93 | Assert.IsTrue(System.Linq.Enumerable.SequenceEqual(arr, intArr)); 94 | 95 | arr.Dispose(); 96 | } 97 | 98 | [Test] 99 | public void ContainsTest() 100 | { 101 | NativeArray arr = new NativeArray(10); 102 | 103 | for (int i = 0; i < 10; i++) 104 | arr[i] = i; 105 | 106 | Assert.IsTrue(arr.Contains(5)); 107 | Assert.IsFalse(arr.Contains(15)); 108 | 109 | arr.Dispose(); 110 | } 111 | 112 | [Test] 113 | public void IndexOfTest() 114 | { 115 | NativeArray arr = new NativeArray(10); 116 | 117 | for (int i = 0; i < 10; i++) 118 | arr[i] = i; 119 | 120 | Assert.AreEqual(3, arr.IndexOf(3)); 121 | Assert.AreEqual(5, arr.LastIndexOf(5)); 122 | 123 | arr.Dispose(); 124 | } 125 | 126 | [Test] 127 | public void EmptyArrayTest() 128 | { 129 | var arr = NativeArray.Empty(); 130 | 131 | Assert.AreEqual(0, arr.Length); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Native/NativeListTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using UnsafeCollections.Collections.Native; 6 | 7 | namespace UnsafeCollectionsTests.Native 8 | { 9 | public class NativeListTests 10 | { 11 | [Test] 12 | public void AddRangeTest() 13 | { 14 | NativeList list = new NativeList(5); 15 | for (int i = 0; i < 5; i++) 16 | list.Add(i); 17 | 18 | List list2 = new List(); 19 | 20 | for (int i = 5; i < 10; i++) 21 | list2.Add(i); 22 | 23 | list.AddRange(list2); 24 | 25 | Assert.AreEqual(10, list.Capacity); 26 | Assert.AreEqual(10, list.Count); 27 | 28 | for (int i = 0; i < 10; i++) 29 | Assert.AreEqual(i, list[i]); 30 | 31 | list.Dispose(); 32 | } 33 | 34 | [Test] 35 | public void IndexOfTest() 36 | { 37 | NativeList list = new NativeList(10); 38 | 39 | for (int i = 0; i < 10; i++) 40 | list.Add(i); 41 | 42 | Assert.AreEqual(7, list.IndexOf(7)); 43 | 44 | list.Dispose(); 45 | } 46 | 47 | [Test] 48 | public void ContainsExplicitTest() 49 | { 50 | ICollection list = new NativeList(10); 51 | 52 | for (int i = 0; i < 10; i++) 53 | list.Add(i); 54 | 55 | Assert.IsTrue(list.Contains(7)); 56 | Assert.IsFalse(list.Contains(11)); 57 | 58 | ((NativeList)list).Dispose(); 59 | } 60 | 61 | [Test] 62 | public void ToNativeArrayTest() 63 | { 64 | NativeList list = new NativeList(10); 65 | 66 | for (int i = 0; i < 10; i++) 67 | list.Add((i + 1) * i); 68 | 69 | var arr = list.ToNativeArray(); 70 | 71 | System.Linq.Enumerable.SequenceEqual(list, arr); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Native/NativeSortedDictionaryTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using UnsafeCollections.Collections.Native; 6 | 7 | namespace UnsafeCollectionsTests.Native 8 | { 9 | public class NativeSortedDictionaryTests 10 | { 11 | [Test] 12 | public void ValueCollectionTest() 13 | { 14 | var dict = PrepareDictionary(); 15 | 16 | var values = dict.Values; 17 | 18 | Assert.AreEqual(4, values.Count); 19 | var itr = values.GetEnumerator(); 20 | 21 | // Check values in expected order. 22 | itr.MoveNext(); 23 | Assert.AreEqual(42, itr.Current); 24 | 25 | itr.MoveNext(); 26 | Assert.AreEqual(254, itr.Current); 27 | 28 | itr.MoveNext(); 29 | Assert.AreEqual(999, itr.Current); 30 | 31 | itr.MoveNext(); 32 | Assert.AreEqual(11, itr.Current); 33 | 34 | } 35 | 36 | [Test] 37 | public void ValuesCopyToTest() 38 | { 39 | var dict = PrepareDictionary(); 40 | var values = dict.Values; 41 | 42 | var arr = new double[4]; 43 | values.CopyTo(arr, 0); 44 | 45 | Assert.AreEqual(42, arr[0]); 46 | Assert.AreEqual(254, arr[1]); 47 | Assert.AreEqual(999, arr[2]); 48 | Assert.AreEqual(11, arr[3]); 49 | } 50 | 51 | [Test] 52 | public void KeyCollectionTest() 53 | { 54 | var dict = PrepareDictionary(); 55 | 56 | var keys = dict.Keys; 57 | 58 | Assert.AreEqual(4, keys.Count); 59 | 60 | var itr = keys.GetEnumerator(); 61 | 62 | // Check values in expected order. 63 | itr.MoveNext(); 64 | Assert.AreEqual(-20, itr.Current); 65 | 66 | itr.MoveNext(); 67 | Assert.AreEqual(1, itr.Current); 68 | 69 | itr.MoveNext(); 70 | Assert.AreEqual(3, itr.Current); 71 | 72 | itr.MoveNext(); 73 | Assert.AreEqual(5, itr.Current); 74 | } 75 | 76 | [Test] 77 | public void KeysCopyToTest() 78 | { 79 | var dict = PrepareDictionary(); 80 | var keys = dict.Keys; 81 | 82 | var arr = new int[4]; 83 | keys.CopyTo(arr, 0); 84 | 85 | Assert.AreEqual(-20, arr[0]); 86 | Assert.AreEqual(1, arr[1]); 87 | Assert.AreEqual(3, arr[2]); 88 | Assert.AreEqual(5, arr[3]); 89 | } 90 | 91 | 92 | private NativeSortedDictionary PrepareDictionary() 93 | { 94 | var dict = new NativeSortedDictionary(8); 95 | 96 | dict.Add(1, 254); // Index 2 97 | dict.Add(5, 11); // Index 4 98 | dict.Add(3, 999); // Index 3 99 | dict.Add(-20, 42); // Index 1 100 | 101 | return dict; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/Concurrent/UnsafeSPSCQueueTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Threading; 4 | using UnsafeCollections; 5 | using UnsafeCollections.Collections.Unsafe.Concurrent; 6 | 7 | namespace UnsafeCollectionsTests.Unsafe.Concurrent 8 | { 9 | public unsafe class UnsafeSPSCQueueTests 10 | { 11 | private static void SplitQueue(UnsafeSPSCQueue* q) 12 | { 13 | //Wrap tail back to 0 14 | for (int i = 0; i < 5; i++) 15 | UnsafeSPSCQueue.Enqueue(q, 111); 16 | 17 | //First half 18 | for (int i = 0; i < 5; i++) 19 | UnsafeSPSCQueue.Enqueue(q, i); 20 | 21 | //Move head by 5 22 | for (int i = 0; i < 5; i++) 23 | UnsafeSPSCQueue.Dequeue(q); 24 | 25 | //Second half (head and tail are now both 5) 26 | for (int i = 5; i < 10; i++) 27 | UnsafeSPSCQueue.Enqueue(q, i); 28 | 29 | //Circular buffer now "ends" in the middle of the underlying array 30 | } 31 | 32 | 33 | [Test] 34 | public void ConstructorTest() 35 | { 36 | var q = UnsafeSPSCQueue.Allocate(10); 37 | 38 | Assert.AreEqual(0, UnsafeSPSCQueue.GetCount(q)); 39 | Assert.AreEqual(10, UnsafeSPSCQueue.GetCapacity(q)); 40 | 41 | UnsafeSPSCQueue.Free(q); 42 | } 43 | 44 | [Test] 45 | public void EnqueueTest() 46 | { 47 | var q = UnsafeSPSCQueue.Allocate(10); 48 | 49 | for (int i = 0; i < 10; i++) 50 | { 51 | UnsafeSPSCQueue.Enqueue(q, i * i); 52 | } 53 | 54 | Assert.AreEqual(10, UnsafeSPSCQueue.GetCount(q)); 55 | Assert.AreEqual(10, UnsafeSPSCQueue.GetCapacity(q)); 56 | 57 | UnsafeSPSCQueue.Clear(q); 58 | 59 | Assert.AreEqual(0, UnsafeSPSCQueue.GetCount(q)); 60 | Assert.AreEqual(10, UnsafeSPSCQueue.GetCapacity(q)); 61 | 62 | UnsafeSPSCQueue.Free(q); 63 | } 64 | 65 | [Test] 66 | public void DequeueTest() 67 | { 68 | var q = UnsafeSPSCQueue.Allocate(10); 69 | 70 | for (int i = 0; i < 10; i++) 71 | UnsafeSPSCQueue.Enqueue(q, i * i); 72 | 73 | for (int i = 0; i < 10; i++) 74 | { 75 | int num = UnsafeSPSCQueue.Dequeue(q); 76 | Assert.AreEqual(i * i, num); 77 | } 78 | 79 | UnsafeSPSCQueue.Free(q); 80 | } 81 | 82 | [Test] 83 | public void PeekTest() 84 | { 85 | var q = UnsafeSPSCQueue.Allocate(10); 86 | 87 | for (int i = 0; i < 10; i++) 88 | UnsafeSPSCQueue.Enqueue(q, (int)Math.Pow(i + 2, 2)); 89 | 90 | for (int i = 0; i < 10; i++) 91 | { 92 | Assert.AreEqual(4, UnsafeSPSCQueue.Peek(q)); 93 | } 94 | 95 | //Verify no items are dequeued 96 | Assert.AreEqual(10, UnsafeSPSCQueue.GetCount(q)); 97 | 98 | UnsafeSPSCQueue.Free(q); 99 | } 100 | 101 | [Test] 102 | public void ExpandTest() 103 | { 104 | var q = UnsafeSPSCQueue.Allocate(16); 105 | 106 | SplitQueue(q); 107 | 108 | //Fill buffer to capacity. 109 | for (int i = 0; i < 6; i++) 110 | UnsafeSPSCQueue.Enqueue(q, 999); 111 | 112 | 113 | //Buffer is full, can no longer insert. 114 | Assert.IsFalse(UnsafeSPSCQueue.TryEnqueue(q, 10)); 115 | 116 | UnsafeSPSCQueue.Free(q); 117 | } 118 | 119 | [Test] 120 | public void TryActionTest() 121 | { 122 | var q = UnsafeSPSCQueue.Allocate(16); 123 | 124 | //Inserts 10 items. 125 | SplitQueue(q); 126 | 127 | //Insert 6 more to fill the queue 128 | for (int i = 0; i < 6; i++) 129 | UnsafeSPSCQueue.TryEnqueue(q, 999); 130 | 131 | Assert.IsFalse(UnsafeSPSCQueue.TryEnqueue(q, 10)); 132 | Assert.IsTrue(UnsafeSPSCQueue.TryPeek(q, out int result)); 133 | Assert.AreEqual(0, result); 134 | 135 | for (int i = 0; i < 10; i++) 136 | { 137 | Assert.IsTrue(UnsafeSPSCQueue.TryDequeue(q, out int val)); 138 | Assert.AreEqual(i, val); 139 | } 140 | 141 | //Empty 6 last items 142 | for (int i = 0; i < 6; i++) 143 | { 144 | Assert.IsTrue(UnsafeSPSCQueue.TryDequeue(q, out int val)); 145 | Assert.AreEqual(999, val); 146 | } 147 | 148 | //Empty queue 149 | Assert.IsFalse(UnsafeSPSCQueue.TryPeek(q, out int res)); 150 | 151 | UnsafeSPSCQueue.Free(q); 152 | } 153 | 154 | [Test] 155 | public void ClearTest() 156 | { 157 | var q = UnsafeSPSCQueue.Allocate(10); 158 | 159 | //Inserts 10 items. 160 | SplitQueue(q); 161 | 162 | Assert.AreEqual(10, UnsafeSPSCQueue.GetCount(q)); 163 | UnsafeSPSCQueue.Clear(q); 164 | Assert.AreEqual(0, UnsafeSPSCQueue.GetCount(q)); 165 | 166 | Assert.IsTrue(UnsafeSPSCQueue.IsEmpty(q)); 167 | 168 | UnsafeSPSCQueue.Free(q); 169 | } 170 | 171 | [Test] 172 | public void IteratorTest() 173 | { 174 | var q = UnsafeSPSCQueue.Allocate(10); 175 | 176 | // Wrap tail around 177 | SplitQueue(q); 178 | 179 | // Iterator should start from the head. 180 | int num = 0; 181 | foreach (int i in UnsafeSPSCQueue.GetEnumerator(q)) 182 | { 183 | Assert.AreEqual(num, i); 184 | num++; 185 | } 186 | 187 | // Iterated 10 items 188 | Assert.AreEqual(10, num); 189 | 190 | UnsafeSPSCQueue.Free(q); 191 | } 192 | 193 | #if DEBUG 194 | [Test] 195 | public void InvalidTypeTest() 196 | { 197 | var q = UnsafeSPSCQueue.Allocate(10); 198 | 199 | Assert.Catch(() => { UnsafeSPSCQueue.Enqueue(q, 162); }); 200 | 201 | UnsafeSPSCQueue.Free(q); 202 | } 203 | #endif 204 | 205 | [Test] 206 | public void CopyToTest() 207 | { 208 | var q = UnsafeSPSCQueue.Allocate(10); 209 | SplitQueue(q); 210 | 211 | var arr = UnsafeSPSCQueue.ToArray(q); 212 | 213 | for (int i = 0; i < 10; i++) 214 | { 215 | Assert.AreEqual(i, arr[i]); 216 | } 217 | } 218 | 219 | [Test] 220 | // Demonstration that this queue is SPSC 221 | public void ConcurrencyTest() 222 | { 223 | var q = UnsafeSPSCQueue.Allocate(16); 224 | int count = 10000; 225 | 226 | Thread reader = new Thread(() => 227 | { 228 | for (int i = 0; i < count; i++) 229 | { 230 | Assert.AreEqual(i, UnsafeSPSCQueue.Dequeue(q)); 231 | } 232 | }); 233 | 234 | reader.Start(); 235 | 236 | for (int i = 0; i < count; i++) 237 | { 238 | UnsafeSPSCQueue.Enqueue(q, i); 239 | } 240 | 241 | reader.Join(); 242 | 243 | UnsafeSPSCQueue.Free(q); 244 | } 245 | 246 | [Test] 247 | //Demonstration that this queue isn't MPSC 248 | public void ConcurrencyTest2() 249 | { 250 | var q = UnsafeSPSCQueue.Allocate(1600000); 251 | int count = 1000000; 252 | 253 | Thread writer = new Thread(() => 254 | { 255 | for (int i = 0; i < count / 2; i++) 256 | UnsafeSPSCQueue.Enqueue(q, i); 257 | }); 258 | Thread writer2 = new Thread(() => 259 | { 260 | for (int i = 0; i < count / 2; i++) 261 | UnsafeSPSCQueue.Enqueue(q, i); 262 | }); 263 | 264 | writer.Start(); 265 | writer2.Start(); 266 | 267 | 268 | writer.Join(); 269 | writer2.Join(); 270 | 271 | Assert.AreNotEqual(count, UnsafeSPSCQueue.GetCount(q)); 272 | 273 | UnsafeSPSCQueue.Free(q); 274 | } 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/UnsafeArrayTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using UnsafeCollections; 3 | using UnsafeCollections.Collections.Unsafe; 4 | 5 | namespace UnsafeCollectionsTests.Unsafe 6 | { 7 | public unsafe class UnsafeArrayTests 8 | { 9 | [Test] 10 | public void ConstructorTest() 11 | { 12 | var arr = UnsafeArray.Allocate(10); 13 | 14 | Assert.AreEqual(UnsafeArray.GetLength(arr), 10); 15 | for (int i = 0; i < 10; i++) 16 | { 17 | Assert.AreEqual(0, UnsafeArray.Get(arr, i)); 18 | } 19 | 20 | UnsafeArray.Free(arr); 21 | } 22 | 23 | [Test] 24 | public void MutateTest() 25 | { 26 | var arr = UnsafeArray.Allocate(10); 27 | 28 | for (int i = 0; i < 10; i++) 29 | { 30 | UnsafeArray.Set(arr, i, i); 31 | } 32 | 33 | for (int i = 0; i < 10; i++) 34 | { 35 | Assert.AreEqual(i, UnsafeArray.Get(arr, i)); 36 | } 37 | 38 | UnsafeArray.Free(arr); 39 | } 40 | 41 | #if DEBUG 42 | [Test] 43 | public void InvalidTypeTest() 44 | { 45 | var arr = UnsafeArray.Allocate(10); 46 | 47 | Assert.Catch(() => { UnsafeArray.Set(arr, 4, 20); }); 48 | 49 | UnsafeArray.Free(arr); 50 | } 51 | #endif 52 | 53 | [Test] 54 | public void IteratorTest() 55 | { 56 | var arr = UnsafeArray.Allocate(10); 57 | 58 | unsafe 59 | { 60 | var itr = UnsafeArray.GetEnumerator(arr); 61 | for (int i = 0; i < 10; i++) 62 | UnsafeArray.Set(arr, i, i * i); 63 | 64 | int num = 0; 65 | foreach (int i in itr) 66 | { 67 | Assert.AreEqual(num * num, i); 68 | num++; 69 | } 70 | } 71 | 72 | UnsafeArray.Free(arr); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/UnsafeBitSetTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using UnsafeCollections.Collections.Unsafe; 3 | 4 | namespace UnsafeCollectionsTests.Unsafe 5 | { 6 | public unsafe class UnsafeBitSetTests 7 | { 8 | [Test] 9 | public void TestBitSet() 10 | { 11 | UnsafeBitSet* bitSet = UnsafeBitSet.Allocate(64); 12 | 13 | UnsafeBitSet.Set(bitSet, 1); 14 | UnsafeBitSet.Set(bitSet, 2); 15 | UnsafeBitSet.Set(bitSet, 3); 16 | UnsafeBitSet.Set(bitSet, 61); 17 | 18 | UnsafeArray* setBits = UnsafeArray.Allocate(UnsafeBitSet.GetSize(bitSet)); 19 | 20 | var setBitsCount = UnsafeBitSet.ToArray(bitSet, setBits); 21 | 22 | for (int i = 0; i < setBitsCount; i++) 23 | { 24 | Assert.IsTrue(UnsafeBitSet.IsSet(bitSet, UnsafeArray.Get(setBits, i))); 25 | } 26 | 27 | UnsafeBitSet.Free(bitSet); 28 | UnsafeArray.Free(setBits); 29 | } 30 | 31 | [Test] 32 | public void BitSetIteratorTest() 33 | { 34 | UnsafeBitSet* bitSet = UnsafeBitSet.Allocate(8); 35 | 36 | for (int i = 0; i < 8; i++) 37 | { 38 | if (i % 2 == 0) 39 | UnsafeBitSet.Set(bitSet, i, true); 40 | } 41 | 42 | int index = 0; 43 | foreach (var set in UnsafeBitSet.GetEnumerator(bitSet)) 44 | { 45 | if (index % 2 == 0) 46 | Assert.IsTrue(set.set); 47 | 48 | index++; 49 | } 50 | 51 | UnsafeBitSet.Free(bitSet); 52 | } 53 | 54 | [Test] 55 | public void BitSetEquals() 56 | { 57 | UnsafeBitSet* bitsetFirst = UnsafeBitSet.Allocate(8); 58 | UnsafeBitSet* bitsetSecond = UnsafeBitSet.Allocate(8); 59 | 60 | for (int i = 0; i < 8; i++) 61 | { 62 | if (i % 2 == 0) 63 | { 64 | UnsafeBitSet.Set(bitsetFirst, i); 65 | UnsafeBitSet.Set(bitsetSecond, i); 66 | 67 | } 68 | } 69 | 70 | Assert.IsTrue(UnsafeBitSet.AreEqual(bitsetFirst, bitsetSecond)); 71 | 72 | UnsafeBitSet.Free(bitsetFirst); 73 | } 74 | 75 | [Test] 76 | public void OddSizeSetTest() 77 | { 78 | UnsafeBitSet* bs = UnsafeBitSet.Allocate(67); 79 | 80 | Assert.AreEqual(67, UnsafeBitSet.GetSize(bs)); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/UnsafeHeapTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using UnsafeCollections.Collections.Unsafe; 3 | 4 | namespace UnsafeCollectionsTests.Unsafe 5 | { 6 | public unsafe class UnsafeHeapTests 7 | { 8 | [Test] 9 | public void ClearHeapTest() 10 | { 11 | var heap = UnsafeHeapMax.Allocate(20); 12 | Assert.AreEqual(0, UnsafeHeapMax.GetCount(heap)); 13 | 14 | UnsafeHeapMax.Push(heap, 3, 10); 15 | UnsafeHeapMax.Push(heap, 1, 1); 16 | UnsafeHeapMax.Push(heap, 2, 5); 17 | 18 | Assert.AreEqual(3, UnsafeHeapMax.GetCount(heap)); 19 | 20 | UnsafeHeapMax.Pop(heap, out int key, out int val); 21 | 22 | Assert.AreEqual(2, UnsafeHeapMax.GetCount(heap)); 23 | Assert.AreEqual(3, key); 24 | Assert.AreEqual(10, val); 25 | 26 | UnsafeHeapMax.Clear(heap); 27 | 28 | Assert.AreEqual(0, UnsafeHeapMax.GetCount(heap)); 29 | 30 | UnsafeHeapMax.Push(heap, 3, 10); 31 | UnsafeHeapMax.Push(heap, 1, 1); 32 | UnsafeHeapMax.Push(heap, 2, 5); 33 | 34 | Assert.AreEqual(3, UnsafeHeapMax.GetCount(heap)); 35 | 36 | UnsafeHeapMax.Free(heap); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/UnsafeListTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using UnsafeCollections; 3 | using UnsafeCollections.Collections.Unsafe; 4 | 5 | namespace UnsafeCollectionsTests.Unsafe 6 | { 7 | public unsafe class UnsafeListTest 8 | { 9 | [Test] 10 | public void ConstructorTest() 11 | { 12 | var arr = UnsafeList.Allocate(10); 13 | 14 | Assert.AreEqual(UnsafeList.GetCount(arr), 0); 15 | 16 | UnsafeList.Free(arr); 17 | } 18 | 19 | [Test] 20 | public void MutateTest() 21 | { 22 | var arr = UnsafeList.Allocate(10); 23 | 24 | for (int i = 0; i < 10; i++) 25 | { 26 | UnsafeList.Add(arr, i); 27 | } 28 | 29 | for (int i = 0; i < 10; i++) 30 | { 31 | Assert.AreEqual(i, UnsafeList.Get(arr, i)); 32 | } 33 | 34 | UnsafeList.Free(arr); 35 | } 36 | 37 | #if DEBUG 38 | [Test] 39 | public void InvalidTypeTest() 40 | { 41 | var arr = UnsafeList.Allocate(10); 42 | 43 | Assert.Catch(() => { UnsafeList.Set(arr, 4, 20); }); 44 | 45 | UnsafeList.Free(arr); 46 | } 47 | #endif 48 | 49 | [Test] 50 | public void IteratorTest() 51 | { 52 | var arr = UnsafeList.Allocate(10); 53 | 54 | var itr = UnsafeList.GetEnumerator(arr); 55 | for (int i = 0; i < 10; i++) 56 | UnsafeList.Add(arr, i * i); 57 | 58 | Assert.AreEqual(10, UnsafeList.GetCount(arr)); 59 | 60 | int num = 0; 61 | foreach (int i in itr) 62 | { 63 | Assert.AreEqual(num * num, i); 64 | num++; 65 | } 66 | 67 | UnsafeList.Free(arr); 68 | } 69 | 70 | [Test] 71 | public void RemoveTest() 72 | { 73 | var arr = UnsafeList.Allocate(10); 74 | for (int i = 1; i <= 10; i++) 75 | UnsafeList.Add(arr, i); 76 | 77 | Assert.AreEqual(10, UnsafeList.GetCount(arr)); 78 | 79 | UnsafeList.RemoveAt(arr, 4); //Remove number 5 80 | Assert.AreEqual(9, UnsafeList.GetCount(arr)); 81 | 82 | int offs = 0; 83 | for (int i = 1; i < 10; i++) 84 | { 85 | if (i == 5) offs++; //Skip previously removed 5 86 | var num = UnsafeList.Get(arr, i - 1); 87 | Assert.AreEqual(i + offs, num); 88 | } 89 | } 90 | 91 | [Test] 92 | public void IndexOfTest() 93 | { 94 | var arr = UnsafeList.Allocate(10); 95 | for (int i = 1; i <= 10; i++) 96 | UnsafeList.Add(arr, i); 97 | 98 | var index = UnsafeList.IndexOf(arr, 5); 99 | Assert.AreEqual(4, index); 100 | } 101 | 102 | [Test] 103 | public void LastIndexOfTest() 104 | { 105 | var arr = UnsafeList.Allocate(10); 106 | for (int i = 1; i <= 10; i++) 107 | UnsafeList.Add(arr, i); 108 | 109 | Assert.AreEqual(4, UnsafeList.LastIndexOf(arr, 5)); 110 | Assert.AreEqual(-1, UnsafeList.LastIndexOf(arr, 645)); 111 | Assert.AreEqual(9, UnsafeList.LastIndexOf(arr, 10)); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/UnsafeLockTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Runtime.CompilerServices; 5 | using System.Text; 6 | using System.Threading; 7 | using UnsafeCollections.Collections.Unsafe; 8 | 9 | namespace UnsafeCollectionsTests.Unsafe 10 | { 11 | public class UnsafeLockTest 12 | { 13 | [Test] 14 | public void LockUnlockTest() 15 | { 16 | UnsafeLock _lock = new UnsafeLock(); 17 | 18 | _lock.Lock(); 19 | 20 | _lock.Unlock(); 21 | } 22 | 23 | [Test] 24 | public void UnlockNoLockTest() 25 | { 26 | UnsafeLock _lock = new UnsafeLock(); 27 | 28 | Assert.Catch(() => { _lock.Unlock(); }); 29 | } 30 | 31 | //[Test] 32 | public void ConcurrencyTest() 33 | { 34 | ConcurrentObject num = new ConcurrentObject(); 35 | int count = 100000; 36 | 37 | Thread t = new Thread(() => 38 | { 39 | for (int i = 0; i < count; i++) 40 | { 41 | num.Add(); 42 | } 43 | }); 44 | Thread t2 = new Thread(() => 45 | { 46 | for (int i = 0; i < count; i++) 47 | { 48 | num.Sub(); 49 | } 50 | }); 51 | 52 | 53 | t.Start(); 54 | t2.Start(); 55 | 56 | t.Join(); 57 | t2.Join(); 58 | 59 | Assert.AreEqual(0, num.Num); 60 | } 61 | 62 | class ConcurrentObject 63 | { 64 | private UnsafeLock _lock; 65 | 66 | public int Num 67 | { 68 | get; private set; 69 | } 70 | 71 | [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] 72 | public void Add() 73 | { 74 | _lock.Lock(); 75 | Num++; 76 | _lock.Unlock(); 77 | } 78 | 79 | [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] 80 | public void Sub() 81 | { 82 | _lock.Lock(); 83 | Num--; 84 | _lock.Unlock(); 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/UnsafeOrderedSetTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using UnsafeCollections; 6 | using UnsafeCollections.Collections.Unsafe; 7 | 8 | namespace UnsafeCollectionsTests.Unsafe 9 | { 10 | public unsafe class UnsafeOrderedSetTests 11 | { 12 | [Test] 13 | public void ConstructorTest() 14 | { 15 | var set = UnsafeSortedSet.Allocate(10); 16 | 17 | Assert.AreEqual(0, UnsafeSortedSet.GetCount(set)); 18 | Assert.AreEqual(10, UnsafeSortedSet.GetCapacity(set)); 19 | 20 | UnsafeSortedSet.Free(set); 21 | } 22 | 23 | #if DEBUG 24 | [Test] 25 | public void InvalidTypeTest() 26 | { 27 | var set = UnsafeSortedSet.Allocate(10); 28 | 29 | Assert.Catch(() => { UnsafeSortedSet.Add(set, 4); }); 30 | 31 | UnsafeSortedSet.Free(set); 32 | } 33 | #endif 34 | 35 | [Test] 36 | public void IteratorTest() 37 | { 38 | var set = UnsafeSortedSet.Allocate(10); 39 | 40 | // Fill set 41 | for (int i = 10; i >= 0; i--) 42 | { 43 | // Add in reverse order 44 | UnsafeSortedSet.Add(set, i); 45 | } 46 | 47 | var enumerator = UnsafeSortedSet.GetEnumerator(set); 48 | 49 | for (int i = 0; i < 10; i++) 50 | { 51 | enumerator.MoveNext(); 52 | Assert.AreEqual(i, enumerator.Current); 53 | } 54 | 55 | UnsafeSortedSet.Free(set); 56 | } 57 | 58 | [Test] 59 | public void ExpandFailedTest() 60 | { 61 | var set = UnsafeSortedSet.Allocate(8, true); 62 | 63 | // Valid adds 64 | for (int i = 0; i < 8; i++) 65 | UnsafeSortedSet.Add(set, i + 1); 66 | 67 | Assert.AreEqual(8, UnsafeSortedSet.GetCount(set)); 68 | Assert.AreEqual(8, UnsafeSortedSet.GetCapacity(set)); 69 | 70 | Assert.Throws(() => 71 | { 72 | UnsafeSortedSet.Add(set, 42); 73 | }); 74 | 75 | UnsafeSortedSet.Free(set); 76 | } 77 | 78 | [Test] 79 | public void ExpandTest() 80 | { 81 | var set = UnsafeSortedSet.Allocate(8, fixedSize: false); 82 | 83 | // Valid adds 84 | for (int i = 0; i < 8; i++) 85 | UnsafeSortedSet.Add(set, i + 1); 86 | 87 | Assert.AreEqual(8, UnsafeSortedSet.GetCount(set)); 88 | Assert.AreEqual(8, UnsafeSortedSet.GetCapacity(set)); 89 | 90 | UnsafeSortedSet.Add(set, 42); 91 | 92 | Assert.AreEqual(9, UnsafeSortedSet.GetCount(set)); 93 | Assert.AreEqual(16, UnsafeSortedSet.GetCapacity(set)); 94 | 95 | UnsafeSortedSet.Free(set); 96 | } 97 | 98 | [Test] 99 | public void ContainsTest() 100 | { 101 | var set = UnsafeSortedSet.Allocate(10); 102 | 103 | Assert.IsFalse(UnsafeSortedSet.Contains(set, 1)); 104 | 105 | UnsafeSortedSet.Add(set, 1); 106 | UnsafeSortedSet.Add(set, 7); 107 | UnsafeSortedSet.Add(set, 51); 108 | UnsafeSortedSet.Add(set, 13); 109 | 110 | Assert.IsFalse(UnsafeSortedSet.Contains(set, 3)); 111 | 112 | Assert.IsTrue(UnsafeSortedSet.Contains(set, 1)); 113 | Assert.IsTrue(UnsafeSortedSet.Contains(set, 7)); 114 | Assert.IsTrue(UnsafeSortedSet.Contains(set, 13)); 115 | Assert.IsTrue(UnsafeSortedSet.Contains(set, 51)); 116 | 117 | Assert.IsFalse(UnsafeSortedSet.Contains(set, 14)); 118 | 119 | UnsafeSortedSet.Free(set); 120 | } 121 | 122 | [Test] 123 | public void RemoveTest() 124 | { 125 | var set = UnsafeSortedSet.Allocate(10); 126 | 127 | Assert.IsFalse(UnsafeSortedSet.Remove(set, 1)); 128 | 129 | UnsafeSortedSet.Add(set, 1); 130 | UnsafeSortedSet.Add(set, 7); 131 | UnsafeSortedSet.Add(set, 51); 132 | UnsafeSortedSet.Add(set, 13); 133 | 134 | Assert.IsFalse(UnsafeSortedSet.Remove(set, 3)); 135 | 136 | Assert.IsTrue(UnsafeSortedSet.Remove(set, 1)); 137 | Assert.IsTrue(UnsafeSortedSet.Remove(set, 7)); 138 | Assert.IsTrue(UnsafeSortedSet.Remove(set, 13)); 139 | Assert.IsTrue(UnsafeSortedSet.Remove(set, 51)); 140 | 141 | Assert.IsFalse(UnsafeSortedSet.Remove(set, 13)); 142 | 143 | UnsafeSortedSet.Free(set); 144 | } 145 | 146 | [Test] 147 | public void AddRandomTest() 148 | { 149 | var set = UnsafeSortedSet.Allocate(10); 150 | 151 | Random r = new Random(); 152 | for (int i = 0; i < 10; i++) 153 | UnsafeSortedSet.Add(set, r.Next()); 154 | 155 | int* arr = stackalloc int[10]; 156 | UnsafeSortedSet.CopyTo(set, arr, 0); 157 | 158 | // Validate values are from low to high 159 | int last = arr[0]; 160 | for (int i = 1; i < 10; i++) 161 | { 162 | Assert.IsTrue(last <= arr[i]); 163 | last = arr[i++]; 164 | } 165 | 166 | UnsafeSortedSet.Free(set); 167 | } 168 | 169 | [Test] 170 | public void CopyToTest() 171 | { 172 | var set = UnsafeSortedSet.Allocate(10); 173 | 174 | // Fill set 175 | for (int i = 10; i >= 0; i--) 176 | UnsafeSortedSet.Add(set, i); 177 | 178 | var count = UnsafeSortedSet.GetCount(set); 179 | int* arr = stackalloc int[count]; 180 | 181 | UnsafeSortedSet.CopyTo(set, arr, 0); 182 | 183 | // Check 184 | int num = 0; 185 | for (int i = 0; i < count; i++) 186 | Assert.AreEqual(i, arr[num++]); 187 | 188 | UnsafeSortedSet.Free(set); 189 | } 190 | 191 | [Test] 192 | public void ClearTest() 193 | { 194 | var set = UnsafeSortedSet.Allocate(16, fixedSize: false); 195 | 196 | // Add some random data 197 | Random r = new Random(); 198 | for (int i = 0; i < 10; i++) 199 | UnsafeSortedSet.Add(set, r.Next()); 200 | 201 | // Verify data has been added 202 | Assert.AreEqual(10, UnsafeSortedSet.GetCount(set)); 203 | Assert.AreEqual(16, UnsafeSortedSet.GetCapacity(set)); 204 | 205 | // Clear set and verify it's cleared 206 | UnsafeSortedSet.Clear(set); 207 | 208 | Assert.AreEqual(0, UnsafeSortedSet.GetCount(set)); 209 | Assert.AreEqual(16, UnsafeSortedSet.GetCapacity(set)); 210 | 211 | 212 | // Validate we can still add data and have it be valid 213 | // Add data to cleared set 214 | for (int i = 10; i >= 0; i--) 215 | UnsafeSortedSet.Add(set, i); 216 | 217 | var count = UnsafeSortedSet.GetCount(set); 218 | int* arr = stackalloc int[count]; 219 | 220 | UnsafeSortedSet.CopyTo(set, arr, 0); 221 | 222 | // Validate data has been written 223 | int num = 0; 224 | for (int i = 0; i < count; i++) 225 | Assert.AreEqual(i, arr[num++]); 226 | 227 | Assert.AreEqual(count, UnsafeSortedSet.GetCount(set)); 228 | Assert.AreEqual(16, UnsafeSortedSet.GetCapacity(set)); 229 | 230 | UnsafeSortedSet.Free(set); 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/UnsafeQueueTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Text; 6 | using System.Threading; 7 | using UnsafeCollections; 8 | using UnsafeCollections.Collections.Unsafe; 9 | 10 | namespace UnsafeCollectionsTests.Unsafe 11 | { 12 | public unsafe class UnsafeQueueTests 13 | { 14 | private static void SplitQueue(UnsafeQueue* q) 15 | { 16 | //Wrap tail back to 0 17 | for (int i = 0; i < 5; i++) 18 | UnsafeQueue.Enqueue(q, 111); 19 | 20 | //First half 21 | for (int i = 0; i < 5; i++) 22 | UnsafeQueue.Enqueue(q, i); 23 | 24 | //Move head by 5 25 | for (int i = 0; i < 5; i++) 26 | UnsafeQueue.Dequeue(q); 27 | 28 | //Second half (head and tail are now both 5) 29 | for (int i = 5; i < 10; i++) 30 | UnsafeQueue.Enqueue(q, i); 31 | 32 | //Circular buffer now "ends" in the middle of the underlying array 33 | } 34 | 35 | 36 | [Test] 37 | public void ConstructorTest() 38 | { 39 | var q = UnsafeQueue.Allocate(10); 40 | 41 | Assert.AreEqual(0, UnsafeQueue.GetCount(q)); 42 | Assert.AreEqual(10, UnsafeQueue.GetCapacity(q)); 43 | Assert.IsFalse(UnsafeQueue.IsFixedSize(q)); 44 | 45 | UnsafeQueue.Free(q); 46 | } 47 | 48 | [Test] 49 | public void EnqueueTest() 50 | { 51 | var q = UnsafeQueue.Allocate(10); 52 | 53 | for (int i = 0; i < 10; i++) 54 | { 55 | UnsafeQueue.Enqueue(q, i * i); 56 | } 57 | 58 | Assert.AreEqual(10, UnsafeQueue.GetCount(q)); 59 | Assert.AreEqual(10, UnsafeQueue.GetCapacity(q)); 60 | 61 | UnsafeQueue.Clear(q); 62 | 63 | Assert.AreEqual(0, UnsafeQueue.GetCount(q)); 64 | Assert.AreEqual(10, UnsafeQueue.GetCapacity(q)); 65 | 66 | UnsafeQueue.Free(q); 67 | } 68 | 69 | [Test] 70 | public void DequeueTest() 71 | { 72 | var q = UnsafeQueue.Allocate(10); 73 | 74 | for (int i = 0; i < 10; i++) 75 | UnsafeQueue.Enqueue(q, i * i); 76 | 77 | 78 | for (int i = 0; i < 10; i++) 79 | { 80 | int num = UnsafeQueue.Dequeue(q); 81 | Assert.AreEqual(i * i, num); 82 | } 83 | 84 | UnsafeQueue.Free(q); 85 | } 86 | 87 | [Test] 88 | public void PeekTest() 89 | { 90 | var q = UnsafeQueue.Allocate(10); 91 | 92 | for (int i = 0; i < 10; i++) 93 | UnsafeQueue.Enqueue(q, (int)Math.Pow(i + 2, 2)); 94 | 95 | for (int i = 0; i < 10; i++) 96 | { 97 | int num = UnsafeQueue.Peek(q); 98 | Assert.AreEqual(4, num); 99 | } 100 | 101 | //Verify no items are dequeued 102 | Assert.AreEqual(10, UnsafeQueue.GetCount(q)); 103 | 104 | UnsafeQueue.Free(q); 105 | } 106 | 107 | [Test] 108 | public void ExpandTest() 109 | { 110 | var q = UnsafeQueue.Allocate(10); 111 | 112 | SplitQueue(q); 113 | 114 | UnsafeQueue.Enqueue(q, 10); 115 | UnsafeQueue.Enqueue(q, 11); 116 | UnsafeQueue.Enqueue(q, 12); 117 | 118 | int num = 0; 119 | foreach (int i in UnsafeQueue.GetEnumerator(q)) 120 | { 121 | Assert.AreEqual(num, i); 122 | num++; 123 | } 124 | 125 | UnsafeQueue.Free(q); 126 | } 127 | 128 | [Test] 129 | public void TryActionTest() 130 | { 131 | var q = UnsafeQueue.Allocate(10, true); 132 | 133 | SplitQueue(q); 134 | 135 | Assert.IsFalse(UnsafeQueue.TryEnqueue(q, 10)); 136 | Assert.IsTrue(UnsafeQueue.TryPeek(q, out int result)); 137 | Assert.AreEqual(0, result); 138 | 139 | for (int i = 0; i < 10; i++) 140 | { 141 | Assert.IsTrue(UnsafeQueue.TryDequeue(q, out int val)); 142 | Assert.AreEqual(i, val); 143 | } 144 | 145 | //Empty queue 146 | Assert.IsFalse(UnsafeQueue.TryPeek(q, out int res)); 147 | 148 | UnsafeQueue.Free(q); 149 | } 150 | 151 | [Test] 152 | public void IteratorTest() 153 | { 154 | var q = UnsafeQueue.Allocate(10); 155 | 156 | //Wrap tail around 157 | SplitQueue(q); 158 | 159 | //Iterator should start from the head. 160 | int num = 0; 161 | foreach (int i in UnsafeQueue.GetEnumerator(q)) 162 | { 163 | Assert.AreEqual(num, i); 164 | num++; 165 | } 166 | 167 | Assert.AreEqual(num, UnsafeQueue.GetCount(q)); 168 | 169 | UnsafeQueue.Free(q); 170 | } 171 | 172 | [Test] 173 | public void Contains() 174 | { 175 | var q = UnsafeQueue.Allocate(10); 176 | 177 | //Wrap tail around 178 | SplitQueue(q); 179 | 180 | 181 | //Check tail and head end of the queue 182 | Assert.IsTrue(UnsafeQueue.Contains(q, 1)); 183 | Assert.IsTrue(UnsafeQueue.Contains(q, 9)); 184 | Assert.False(UnsafeQueue.Contains(q, 11)); 185 | 186 | UnsafeQueue.Free(q); 187 | } 188 | 189 | #if DEBUG 190 | [Test] 191 | public void InvalidTypeTest() 192 | { 193 | var q = UnsafeQueue.Allocate(10); 194 | 195 | Assert.Catch(() => { UnsafeQueue.Enqueue(q, 162); }); 196 | 197 | UnsafeQueue.Free(q); 198 | } 199 | #endif 200 | 201 | [Test] 202 | public void CopyToTest() 203 | { 204 | var q = UnsafeQueue.Allocate(10); 205 | SplitQueue(q); 206 | 207 | var arr = new int[10]; 208 | fixed (void* ptr = arr) 209 | { 210 | UnsafeQueue.CopyTo(q, ptr, 0); 211 | } 212 | 213 | for (int i = 0; i < 10; i++) 214 | { 215 | Assert.AreEqual(i, arr[i]); 216 | } 217 | } 218 | 219 | [Test] 220 | //Demonstration that this queue is not thread safe! 221 | public void ConcurrencyTest() 222 | { 223 | int count = 10000; 224 | var q = UnsafeQueue.Allocate(16, true); 225 | int faulted = 0; 226 | 227 | Thread reader = new Thread(() => 228 | { 229 | for (int i = 0; i < count; i++) 230 | { 231 | if (UnsafeQueue.TryDequeue(q, out int result)) 232 | { 233 | if (i != result) 234 | { 235 | Interlocked.Increment(ref faulted); 236 | break; 237 | } 238 | } 239 | } 240 | }); 241 | 242 | reader.Start(); 243 | 244 | for (int i = 0; i < count;) 245 | { 246 | if (faulted != 0) 247 | break; 248 | 249 | if (UnsafeQueue.TryEnqueue(q, i)) 250 | { 251 | i++; 252 | } 253 | } 254 | 255 | reader.Join(); 256 | 257 | Assert.IsTrue(faulted > 0); 258 | UnsafeQueue.Free(q); 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/UnsafeRingBufferTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using UnsafeCollections; 6 | using UnsafeCollections.Collections.Unsafe; 7 | 8 | namespace UnsafeCollectionsTests.Unsafe 9 | { 10 | public unsafe class UnsafeRingBufferTests 11 | { 12 | private static void SplitRingBuffer(UnsafeRingBuffer* q) 13 | { 14 | //Wrap tail back to 0 15 | for (int i = 0; i < 5; i++) 16 | UnsafeRingBuffer.Push(q, 111); 17 | 18 | //First half 19 | for (int i = 0; i < 5; i++) 20 | UnsafeRingBuffer.Push(q, i); 21 | 22 | //Move head by 5 23 | for (int i = 0; i < 5; i++) 24 | UnsafeRingBuffer.Pop(q, out _); 25 | 26 | //Second half (head and tail are now both 5) 27 | for (int i = 5; i < 10; i++) 28 | UnsafeRingBuffer.Push(q, i); 29 | 30 | //Circular buffer now "ends" in the middle of the underlying array 31 | } 32 | 33 | 34 | [Test] 35 | public void ConstructorTest() 36 | { 37 | var q = UnsafeRingBuffer.Allocate(10); 38 | 39 | Assert.AreEqual(0, UnsafeRingBuffer.GetCount(q)); 40 | Assert.AreEqual(10, UnsafeRingBuffer.GetCapacity(q)); 41 | 42 | UnsafeRingBuffer.Free(q); 43 | } 44 | 45 | [Test] 46 | public void PushTest() 47 | { 48 | var q = UnsafeRingBuffer.Allocate(10); 49 | 50 | for (int i = 0; i < 10; i++) 51 | { 52 | UnsafeRingBuffer.Push(q, i * i); 53 | } 54 | 55 | Assert.AreEqual(10, UnsafeRingBuffer.GetCount(q)); 56 | Assert.AreEqual(10, UnsafeRingBuffer.GetCapacity(q)); 57 | 58 | UnsafeRingBuffer.Clear(q); 59 | 60 | Assert.AreEqual(0, UnsafeRingBuffer.GetCount(q)); 61 | Assert.AreEqual(10, UnsafeRingBuffer.GetCapacity(q)); 62 | 63 | UnsafeRingBuffer.Free(q); 64 | } 65 | 66 | [Test] 67 | public void DequeueTest() 68 | { 69 | var q = UnsafeRingBuffer.Allocate(10); 70 | 71 | for (int i = 0; i < 10; i++) 72 | UnsafeRingBuffer.Push(q, i * i); 73 | 74 | 75 | for (int i = 0; i < 10; i++) 76 | { 77 | UnsafeRingBuffer.Pop(q, out int num); 78 | Assert.AreEqual(i * i, num); 79 | } 80 | 81 | UnsafeRingBuffer.Free(q); 82 | } 83 | 84 | [Test] 85 | public void PeekTest() 86 | { 87 | var q = UnsafeRingBuffer.Allocate(10); 88 | 89 | for (int i = 0; i < 10; i++) 90 | UnsafeRingBuffer.Push(q, (int)Math.Pow(i + 2, 2)); 91 | 92 | for (int i = 0; i < 10; i++) 93 | { 94 | UnsafeRingBuffer.Peek(q, out int num); 95 | Assert.AreEqual(4, num); 96 | } 97 | 98 | //Verify no items are dequeued 99 | Assert.AreEqual(10, UnsafeRingBuffer.GetCount(q)); 100 | 101 | UnsafeRingBuffer.Free(q); 102 | } 103 | 104 | [Test] 105 | public void IteratorTest() 106 | { 107 | var q = UnsafeRingBuffer.Allocate(10); 108 | 109 | //Wrap tail around 110 | SplitRingBuffer(q); 111 | 112 | //Iterator should start from the head. 113 | int num = 0; 114 | foreach (int i in UnsafeRingBuffer.GetEnumerator(q)) 115 | { 116 | Assert.AreEqual(num, i); 117 | num++; 118 | } 119 | 120 | Assert.AreEqual(num, UnsafeRingBuffer.GetCount(q)); 121 | 122 | UnsafeRingBuffer.Free(q); 123 | } 124 | 125 | [Test] 126 | public void Contains() 127 | { 128 | var q = UnsafeRingBuffer.Allocate(10); 129 | 130 | //Wrap tail around 131 | SplitRingBuffer(q); 132 | 133 | 134 | //Check tail and head end of the queue 135 | Assert.IsTrue(UnsafeRingBuffer.Contains(q, 1)); 136 | Assert.IsTrue(UnsafeRingBuffer.Contains(q, 9)); 137 | Assert.False(UnsafeRingBuffer.Contains(q, 11)); 138 | 139 | UnsafeRingBuffer.Free(q); 140 | } 141 | 142 | #if DEBUG 143 | [Test] 144 | public void InvalidTypeTest() 145 | { 146 | var q = UnsafeRingBuffer.Allocate(10); 147 | 148 | Assert.Catch(() => { UnsafeRingBuffer.Push(q, 162); }); 149 | 150 | UnsafeRingBuffer.Free(q); 151 | } 152 | #endif 153 | 154 | [Test] 155 | public void CopyToTest() 156 | { 157 | var q = UnsafeRingBuffer.Allocate(10); 158 | SplitRingBuffer(q); 159 | 160 | var arr = new int[10]; 161 | fixed (void* ptr = arr) 162 | { 163 | UnsafeRingBuffer.CopyTo(q, ptr, 0); 164 | } 165 | 166 | for (int i = 0; i < 10; i++) 167 | { 168 | Assert.AreEqual(i, arr[i]); 169 | } 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/Unsafe/UnsafeStackTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using UnsafeCollections; 6 | using UnsafeCollections.Collections.Unsafe; 7 | 8 | namespace UnsafeCollectionsTests.Unsafe 9 | { 10 | public unsafe class UnsafeStackTests 11 | { 12 | [Test] 13 | public void ConstructorTest() 14 | { 15 | var arr = UnsafeStack.Allocate(10); 16 | 17 | Assert.AreEqual(UnsafeStack.GetCount(arr), 0); 18 | 19 | UnsafeStack.Free(arr); 20 | } 21 | 22 | [Test] 23 | public void MutateTest() 24 | { 25 | var arr = UnsafeStack.Allocate(10); 26 | 27 | for (int i = 0; i < 10; i++) 28 | { 29 | UnsafeStack.Push(arr, i); 30 | } 31 | 32 | for (int i = 9; i >= 0; i--) 33 | { 34 | Assert.AreEqual(i, UnsafeStack.Pop(arr)); 35 | } 36 | 37 | UnsafeStack.Free(arr); 38 | } 39 | 40 | [Test] 41 | public void ExpandTest() 42 | { 43 | var arr = UnsafeStack.Allocate(8); 44 | 45 | for (int i = 0; i < 10; i++) 46 | { 47 | UnsafeStack.Push(arr, i); 48 | } 49 | 50 | Assert.IsTrue(UnsafeStack.GetCapacity(arr) > 8); 51 | 52 | UnsafeStack.Free(arr); 53 | } 54 | 55 | #if DEBUG 56 | [Test] 57 | public void InvalidTypeTest() 58 | { 59 | var arr = UnsafeStack.Allocate(10); 60 | 61 | Assert.Catch(() => { UnsafeStack.Push(arr, 20); }); 62 | 63 | UnsafeStack.Free(arr); 64 | } 65 | #endif 66 | 67 | [Test] 68 | public void IteratorTest() 69 | { 70 | var arr = UnsafeStack.Allocate(10); 71 | 72 | for (int i = 0; i < 10; i++) 73 | UnsafeStack.Push(arr, i); 74 | 75 | Assert.AreEqual(10, UnsafeStack.GetCount(arr)); 76 | 77 | int num = 9; 78 | foreach (int i in UnsafeStack.GetEnumerator(arr)) 79 | { 80 | Assert.AreEqual(num--, i); 81 | } 82 | 83 | UnsafeStack.Free(arr); 84 | } 85 | 86 | [Test] 87 | public void PopTest() 88 | { 89 | var arr = UnsafeStack.Allocate(10); 90 | for (int i = 1; i <= 10; i++) 91 | UnsafeStack.Push(arr, i); 92 | 93 | Assert.AreEqual(10, UnsafeStack.GetCount(arr)); 94 | 95 | var val = UnsafeStack.Pop(arr); 96 | Assert.AreEqual(10, val); 97 | Assert.AreEqual(9, UnsafeStack.GetCount(arr)); 98 | 99 | // Reverse stack-iteration 100 | for (int i = 9; i > 0; i--) 101 | { 102 | var num = UnsafeStack.Pop(arr); 103 | Assert.AreEqual(i, num); 104 | } 105 | 106 | Assert.AreEqual(0, UnsafeStack.GetCount(arr)); 107 | } 108 | 109 | [Test] 110 | public void ContainsTest() 111 | { 112 | var arr = UnsafeStack.Allocate(10); 113 | for (int i = 1; i <= 10; i++) 114 | UnsafeStack.Push(arr, i); 115 | 116 | Assert.IsTrue(UnsafeStack.Contains(arr, 1)); 117 | Assert.IsTrue(UnsafeStack.Contains(arr, 10)); 118 | Assert.IsFalse(UnsafeStack.Contains(arr, 11)); 119 | } 120 | 121 | [Test] 122 | public void CopyToTest() 123 | { 124 | var q = UnsafeStack.Allocate(10); 125 | 126 | for (int i = 0; i < 10; i++) 127 | { 128 | UnsafeStack.Push(q, i); 129 | } 130 | 131 | var arr = new int[10]; 132 | fixed (void* ptr = arr) 133 | { 134 | UnsafeStack.CopyTo(q, ptr, 0); 135 | } 136 | 137 | int num = 10; 138 | for (int i = 0; i < 10; i++) 139 | { 140 | Assert.AreEqual(--num, arr[i]); 141 | } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /UnsafeCollectionsTests/UnsafeCollectionsTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.1 5 | 6 | false 7 | 8 | 7.3 9 | 10 | 11 | 12 | true 13 | 14 | 15 | 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | --------------------------------------------------------------------------------