├── .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