├── NativeCollection
├── .idea
│ └── .idea.NativeCollection
│ │ └── .idea
│ │ ├── vcs.xml
│ │ ├── indexLayout.xml
│ │ └── .gitignore
├── NativeCollection
│ ├── INativeCollectionClass.cs
│ ├── NativeCollection.csproj
│ ├── UnsafeType
│ │ ├── Map
│ │ │ ├── MapPair.cs
│ │ │ └── Map.cs
│ │ ├── NativeStackPool.cs
│ │ ├── MultiMap
│ │ │ ├── MultiMapPair.cs
│ │ │ └── MultiMap.cs
│ │ ├── HashHelpers.cs
│ │ ├── Stack.cs
│ │ ├── Queue.cs
│ │ ├── List.cs
│ │ ├── SortedSet
│ │ │ └── Node.cs
│ │ ├── HashSet.cs
│ │ └── UnOrderMap
│ │ │ └── UnOrderMap.cs
│ ├── NativePool.cs
│ ├── Stack.cs
│ ├── Queue.cs
│ ├── HashSet.cs
│ ├── Map.cs
│ ├── SortedSet.cs
│ ├── MultiMap.cs
│ ├── ThrowHelper.cs
│ ├── NativeMemoryHelper.cs
│ ├── UnOrderMap.cs
│ ├── List.cs
│ └── FixedSizeMemoryPool
│ │ ├── FixedSizeMemoryPool.cs
│ │ └── Slab.cs
├── Benchmark
│ ├── Program.cs
│ ├── Benchmark.csproj
│ └── Benchmarks
│ │ ├── BenchmarkMemoryPool.cs
│ │ ├── BenchmarkHashSet.cs
│ │ ├── BenchmarkSortedSet.cs
│ │ ├── BenchmarkMap.cs
│ │ ├── BenchmarkUnOrderMap.cs
│ │ └── BenchmarkMultiMap.cs
├── NativeCollection.Test
│ ├── NativeCollection.Test.csproj
│ ├── MultiMapTest.cs
│ ├── UnOrderMapTest.cs
│ ├── MapTest.cs
│ ├── QueueTest.cs
│ ├── HashSetTest.cs
│ ├── StackTest.cs
│ ├── SortedSetTest.cs
│ └── ListTest.cs
├── MemoryProfile
│ ├── MemoryProfile.csproj
│ └── MemoryLeakTest.cs
└── NativeCollection.sln
├── LICENSE
├── .gitignore
└── README.md
/NativeCollection/.idea/.idea.NativeCollection/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/NativeCollection/.idea/.idea.NativeCollection/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/INativeCollectionClass.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NativeCollection
4 | {
5 | public interface INativeCollectionClass : IDisposable
6 | {
7 | void ReInit();
8 |
9 | bool IsDisposed { get; }
10 | }
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/NativeCollection/.idea/.idea.NativeCollection/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /modules.xml
6 | /contentModel.xml
7 | /.idea.NativeCollection.iml
8 | /projectSettingsUpdater.xml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/NativeCollection.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 11
5 | true
6 | net7.0
7 | enable
8 |
9 |
10 |
11 |
12 | TRACE;
13 |
14 |
15 |
--------------------------------------------------------------------------------
/NativeCollection/Benchmark/Program.cs:
--------------------------------------------------------------------------------
1 | // See https://aka.ms/new-console-template for more information
2 |
3 | using System.Diagnostics;
4 | using Benchmark.Benchmarks;
5 | using BenchmarkDotNet.Running;
6 | using NativeCollection;
7 | using NativeCollection.UnsafeType;
8 |
9 | public static class Program
10 | {
11 | public static void Main()
12 | {
13 | //var summary = BenchmarkRunner.Run(typeof(Program).Assembly);
14 | var summary = BenchmarkRunner.Run();
15 |
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/NativeCollection/Benchmark/Benchmark.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 | enable
7 | enable
8 | true
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection.Test/NativeCollection.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 susices
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/UnsafeType/Map/MapPair.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace NativeCollection.UnsafeType
5 | {
6 | public unsafe struct MapPair : IEquatable>, IComparable>
7 | where T : unmanaged, IEquatable, IComparable where K : unmanaged, IEquatable
8 | {
9 | public T Key { get; private set; }
10 | public K Value => _value;
11 |
12 | internal K _value;
13 |
14 | public MapPair(T key,K value = default)
15 | {
16 | Key = key;
17 | _value = value;
18 | }
19 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
20 | public bool Equals(MapPair other)
21 | {
22 | return Key.Equals(other.Key);
23 | }
24 |
25 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
26 | public int CompareTo(MapPair other)
27 | {
28 | return Key.CompareTo(other.Key);
29 | }
30 |
31 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
32 | public override int GetHashCode()
33 | {
34 | return Key.GetHashCode();
35 | }
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/NativeCollection/MemoryProfile/MemoryProfile.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 | enable
7 | enable
8 | true
9 |
10 |
11 |
12 | TRACE;MEMORY_PROFILE
13 |
14 |
15 |
16 | TRACE;MEMORY_PROFILE
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | NativeCollection/%(RecursiveDir)%(FileName)%(Extension)
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/NativeCollection/Benchmark/Benchmarks/BenchmarkMemoryPool.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using BenchmarkDotNet.Attributes;
3 | using BenchmarkDotNet.Configs;
4 | using NativeCollection;
5 | using NativeCollection.UnsafeType;
6 |
7 | namespace Benchmark.Benchmarks;
8 | [ShortRunJob]
9 | [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
10 | [CategoriesColumn]
11 | public class BenchmarkMemoryPool
12 | {
13 | [BenchmarkCategory("Alloc")]
14 | [Benchmark]
15 | public void MemoryPoolAlloc()
16 | {
17 | unsafe
18 | {
19 | FixedSizeMemoryPool* memoryPool =FixedSizeMemoryPool.Create(32, 32);
20 | for (int i = 0; i < 10000; i++)
21 | {
22 | var ptr = memoryPool->Alloc();
23 | int* value = (int*)ptr;
24 | *value = i;
25 | }
26 |
27 | memoryPool->Dispose();
28 | }
29 | }
30 |
31 | [BenchmarkCategory("Alloc")]
32 | [Benchmark(Baseline = true)]
33 | public void NativeMemoryAlloc()
34 | {
35 | unsafe
36 | {
37 | for (int i = 0; i < 10000; i++)
38 | {
39 | var ptr = NativeMemory.Alloc(32);
40 | int* value = (int*)ptr;
41 | *value = i;
42 | }
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/NativePool.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using NativeCollection.UnsafeType;
4 |
5 | namespace NativeCollection
6 | {
7 | public unsafe class NativePool : INativeCollectionClass where T: unmanaged,IEquatable,IPool
8 | {
9 | private UnsafeType.NativeStackPool* _nativePool;
10 | private const int _defaultPoolSize = 200;
11 | private int _poolSize;
12 | public NativePool(int maxPoolSize = _defaultPoolSize)
13 | {
14 | _poolSize = maxPoolSize;
15 | _nativePool = UnsafeType.NativeStackPool.Create(_poolSize);
16 | IsDisposed = false;
17 | }
18 |
19 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
20 | public T* Alloc()
21 | {
22 | return _nativePool->Alloc();
23 | }
24 |
25 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
26 | public void Return(T* ptr)
27 | {
28 | _nativePool->Return(ptr);
29 | }
30 |
31 | public void Dispose()
32 | {
33 | if (IsDisposed)
34 | {
35 | return;
36 | }
37 | if (_nativePool != null)
38 | {
39 | _nativePool->Dispose();
40 | NativeMemoryHelper.Free(_nativePool);
41 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf>());
42 | IsDisposed = true;
43 | }
44 | }
45 |
46 | public void ReInit()
47 | {
48 | if (IsDisposed)
49 | {
50 | _nativePool = UnsafeType.NativeStackPool.Create(_poolSize);
51 | IsDisposed = false;
52 | }
53 | }
54 |
55 | public bool IsDisposed { get; private set; }
56 | }
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 |
11 | [Dd]ebug/
12 | [Rr]elease/
13 | x64/
14 | [Bb]in/
15 | [Oo]bj/
16 |
17 | # MSTest test Results
18 | [Tt]est[Rr]esult*/
19 | [Bb]uild[Ll]og.*
20 |
21 | *_i.c
22 | *_p.c
23 | *_i.h
24 | *.ilk
25 | *.meta
26 | *.obj
27 | *.pch
28 | *.pdb
29 | *.pgc
30 | *.pgd
31 | *.rsp
32 | *.sbr
33 | *.tlb
34 | *.tli
35 | *.tlh
36 | *.tmp
37 | *.tmp_proj
38 | *.log
39 | *.vspscc
40 | *.vssscc
41 | .builds
42 | *.pidb
43 | *.log
44 | *.svclog
45 | *.scc
46 |
47 | # Visual C++ cache files
48 | ipch/
49 | *.aps
50 | *.ncb
51 | *.opensdf
52 | *.sdf
53 | *.cachefile
54 |
55 | # Visual Studio profiler
56 | *.psess
57 | *.vsp
58 | *.vspx
59 |
60 | # Guidance Automation Toolkit
61 | *.gpState
62 |
63 | # ReSharper is a .NET coding add-in
64 | _ReSharper*/
65 | *.[Rr]e[Ss]harper
66 | *.DotSettings.user
67 |
68 | # Click-Once directory
69 | publish/
70 |
71 | # Publish Web Output
72 | *.Publish.xml
73 | *.pubxml
74 | *.azurePubxml
75 |
76 | # NuGet Packages Directory
77 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
78 | packages/
79 | ## TODO: If the tool you use requires repositories.config, also uncomment the next line
80 | !packages/repositories.config
81 |
82 | # Windows Azure Build Output
83 | csx/
84 | *.build.csdef
85 |
86 | # Windows Store app package directory
87 | AppPackages/
88 |
89 | # Others
90 | sql/
91 | *.Cache
92 | ClientBin/
93 | [Ss]tyle[Cc]op.*
94 | ![Ss]tyle[Cc]op.targets
95 | ~$*
96 | *~
97 | *.dbmdl
98 | *.[Pp]ublish.xml
99 |
100 | *.publishsettings
101 |
102 | # RIA/Silverlight projects
103 | Generated_Code/
104 |
105 | # Backup & report files from converting an old project file to a newer
106 | # Visual Studio version. Backup files are not needed, because we have git ;-)
107 | _UpgradeReport_Files/
108 | Backup*/
109 | UpgradeLog*.XML
110 | UpgradeLog*.htm
111 |
112 | # SQL Server files
113 | App_Data/*.mdf
114 | App_Data/*.ldf
115 |
116 | # =========================
117 | # Windows detritus
118 | # =========================
119 |
120 | # Windows image file caches
121 | Thumbs.db
122 | ehthumbs.db
123 |
124 | # Folder config file
125 | Desktop.ini
126 |
127 | # Recycle Bin used on file shares
128 | $RECYCLE.BIN/
129 |
130 | # Mac desktop service store files
131 | .DS_Store
132 |
133 | _NCrunch*
134 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection.Test/MultiMapTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Xunit;
3 |
4 | namespace NativeCollection.Test;
5 |
6 | public class MultiMapTest
7 | {
8 | [Fact]
9 | public void AddRemove()
10 | {
11 | MultiMap multiMap = new MultiMap();
12 | multiMap.Add(1,11);
13 | multiMap.Count.Should().Be(1);
14 | multiMap.Add(1,12);
15 | multiMap.Count.Should().Be(1);
16 | multiMap.Add(3,44);
17 | multiMap.Count.Should().Be(2);
18 | multiMap.Remove(3, 44).Should().Be(true);
19 | multiMap.Count.Should().Be(1);
20 | multiMap.Clear();
21 | multiMap.Count.Should().Be(0);
22 | multiMap.Remove(1).Should().Be(false);
23 | multiMap.Remove(1, 4).Should().Be(false);
24 |
25 | multiMap.Clear();
26 | for (int i = 0; i < 1000; i++)
27 | {
28 | multiMap.Add(1,Random.Shared.Next());
29 | }
30 | multiMap.Count.Should().Be(1);
31 | }
32 |
33 | [Fact]
34 | public void Enumerator()
35 | {
36 | SortedDictionary sortedDictionary = new SortedDictionary();
37 | MultiMap multiMap = new MultiMap();
38 |
39 | for (int i = 0; i < 1000; i++)
40 | {
41 | int value = Random.Shared.Next();
42 | sortedDictionary.Add(value,1);
43 | multiMap.Add(value,1);
44 | }
45 |
46 | var MultiMapEnumerator = multiMap.GetEnumerator();
47 | var sortedDictionaryEnumerator = sortedDictionary.GetEnumerator();
48 | while (sortedDictionaryEnumerator.MoveNext())
49 | {
50 | MultiMapEnumerator.MoveNext();
51 | int key = sortedDictionaryEnumerator.Current.Key;
52 | MultiMapEnumerator.Current.Key.Should().Be(key);
53 | }
54 | }
55 |
56 |
57 | [Fact]
58 | public void NativeCollectionClass()
59 | {
60 | MultiMap multiMap = new MultiMap();
61 | multiMap.IsDisposed.Should().Be(false);
62 | for (int i = 0; i < 100; i++)
63 | {
64 | multiMap.Add(Random.Shared.Next(),1);
65 | }
66 | multiMap.Dispose();
67 | multiMap.IsDisposed.Should().Be(true);
68 | multiMap.ReInit();
69 | multiMap.IsDisposed.Should().Be(false);
70 | multiMap.Count.Should().Be(0);
71 | for (int i = 0; i < 100; i++)
72 | {
73 | multiMap.Add(Random.Shared.Next(),1);
74 | }
75 | }
76 |
77 | }
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/UnsafeType/NativeStackPool.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace NativeCollection.UnsafeType
5 | {
6 | public interface IPool : IDisposable
7 | {
8 | public void OnReturnToPool();
9 | public void OnGetFromPool();
10 | }
11 |
12 | public unsafe struct NativeStackPool : IDisposable where T: unmanaged,IPool
13 | {
14 | public int MaxSize { get; private set; }
15 | private Stack* _stack;
16 | public static NativeStackPool* Create(int maxPoolSize)
17 | {
18 | NativeStackPool* pool = (NativeStackPool*)NativeMemoryHelper.Alloc((UIntPtr)Unsafe.SizeOf>());
19 | pool->_stack = Stack.Create();
20 | pool->MaxSize = maxPoolSize;
21 | return pool;
22 | }
23 |
24 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
25 | public T* Alloc()
26 | {
27 | if (_stack->TryPop(out var itemPtr))
28 | {
29 | var item = (T*)itemPtr;
30 | item->OnGetFromPool();
31 | return item;
32 | }
33 | return null;
34 | }
35 |
36 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
37 | public void Return(T* ptr)
38 | {
39 | if (_stack->Count>=MaxSize)
40 | {
41 | ptr->Dispose();
42 | NativeMemoryHelper.Free(ptr);
43 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf());
44 | return;
45 | }
46 | ptr->OnReturnToPool();
47 | _stack->Push(new IntPtr(ptr));
48 | }
49 |
50 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 | public bool IsPoolMax()
52 | {
53 | return _stack->Count >= MaxSize;
54 | }
55 |
56 | public void Clear()
57 | {
58 | while (_stack->TryPop(out var ptr))
59 | {
60 | T* item = (T*)ptr;
61 | item->Dispose();
62 | NativeMemoryHelper.Free(item);
63 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf());
64 | }
65 | }
66 |
67 | public void Dispose()
68 | {
69 | Clear();
70 | _stack->Dispose();
71 | NativeMemoryHelper.Free(_stack);
72 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf>());
73 | }
74 | }
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/Stack.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace NativeCollection
5 | {
6 | public unsafe class Stack : INativeCollectionClass where T : unmanaged
7 | {
8 | private const int _defaultCapacity = 10;
9 | private UnsafeType.Stack* _stack;
10 | private int _capacity;
11 | public Stack(int initialCapacity = _defaultCapacity)
12 | {
13 | _capacity = initialCapacity;
14 | _stack = UnsafeType.Stack.Create(_capacity);
15 | IsDisposed = false;
16 | }
17 |
18 | public int Count => _stack->Count;
19 |
20 | public void Dispose()
21 | {
22 | if (IsDisposed)
23 | {
24 | return;
25 | }
26 | if (_stack != null)
27 | {
28 | _stack->Dispose();
29 | NativeMemoryHelper.Free(_stack);
30 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf>());
31 | IsDisposed = true;
32 | }
33 | }
34 |
35 | public void Clear()
36 | {
37 | _stack->Clear();
38 | }
39 |
40 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
41 | public bool Contains(in T obj)
42 | {
43 | return _stack->Contains(obj);
44 | }
45 |
46 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
47 | public T Peak()
48 | {
49 | return _stack->Peak();
50 | }
51 |
52 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
53 | public T Pop()
54 | {
55 | return _stack->Pop();
56 | }
57 |
58 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
59 | public bool TryPop(out T result)
60 | {
61 | var returnValue = _stack->TryPop(out result);
62 | return returnValue;
63 | }
64 |
65 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
66 | public void Push(in T obj)
67 | {
68 | _stack->Push(obj);
69 | }
70 |
71 | ~Stack()
72 | {
73 | Dispose();
74 | }
75 |
76 | public void ReInit()
77 | {
78 | if (IsDisposed)
79 | {
80 | _stack = UnsafeType.Stack.Create(_capacity);
81 | IsDisposed = false;
82 | }
83 | }
84 |
85 | public bool IsDisposed { get; private set; }
86 | }
87 | }
88 |
89 |
90 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/UnsafeType/MultiMap/MultiMapPair.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace NativeCollection.UnsafeType
5 | {
6 | public unsafe struct MultiMapPair : IEquatable>, IComparable>
7 | where T : unmanaged, IEquatable, IComparable where K : unmanaged, IEquatable
8 | {
9 | private UnsafeType.List* _value;
10 |
11 | public T Key { get; private set; }
12 |
13 | public ref UnsafeType.List Value
14 | {
15 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
16 | get { return ref Unsafe.AsRef>(_value); }
17 | }
18 |
19 | public MultiMapPair(T key)
20 | {
21 | Key = key;
22 | _value = null;
23 | }
24 |
25 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
26 | public static MultiMapPair Create(in T key, FixedSizeMemoryPool* pool, NativeStackPool>* stackPool)
27 | {
28 | var pair = new MultiMapPair(key);
29 | List* list = stackPool->Alloc();
30 | if (list==null)
31 | {
32 | list = List.AllocFromMemoryPool(pool);
33 | }
34 | pair._value = list;
35 | return pair;
36 | }
37 |
38 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 | public bool Equals(MultiMapPair other)
40 | {
41 | return Key.Equals(other.Key);
42 | }
43 |
44 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 | public int CompareTo(MultiMapPair other)
46 | {
47 | return Key.CompareTo(other.Key);
48 | }
49 |
50 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 | public override int GetHashCode()
52 | {
53 | return Key.GetHashCode();
54 | }
55 |
56 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
57 | public void Dispose(FixedSizeMemoryPool* pool,NativeStackPool>* stackPool)
58 | {
59 | if (_value!=null)
60 | {
61 | if (!stackPool->IsPoolMax())
62 | {
63 | stackPool->Return(_value);
64 | _value = null;
65 | }
66 | else
67 | {
68 | _value->Dispose();
69 | pool->Free(_value);
70 | }
71 | }
72 | }
73 | }
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection.Test/UnOrderMapTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Xunit;
3 |
4 | namespace NativeCollection.Test;
5 |
6 | public class UnOrderMapTest
7 | {
8 | [Fact]
9 | public void AddRemove()
10 | {
11 | UnOrderMap unOrderMap = new UnOrderMap();
12 | unOrderMap.Add(1,11);
13 | unOrderMap.Count.Should().Be(1);
14 | unOrderMap[1].Should().Be(11);
15 | unOrderMap.Count.Should().Be(1);
16 | unOrderMap[1].Should().Be(11);
17 | unOrderMap.Add(3,44);
18 | unOrderMap.Count.Should().Be(2);
19 | unOrderMap.Remove(3).Should().Be(true);
20 | unOrderMap.Count.Should().Be(1);
21 | unOrderMap.Clear();
22 | unOrderMap.Count.Should().Be(0);
23 | unOrderMap.Remove(1).Should().Be(false);
24 | unOrderMap.Clear();
25 |
26 | unOrderMap.Clear();
27 | unOrderMap.Add(1,100);
28 | unOrderMap[1].Should().Be(100);
29 | unOrderMap[1] = 101;
30 | unOrderMap[1].Should().Be(101);
31 | unOrderMap[2] = 102;
32 | unOrderMap[2].Should().Be(102);
33 | }
34 |
35 | [Fact]
36 | public void Enumerator()
37 | {
38 | Dictionary dictionary = new Dictionary();
39 | UnOrderMap unOrderMap = new UnOrderMap();
40 |
41 | for (int i = 0; i < 1000; i++)
42 | {
43 | int value = Random.Shared.Next();
44 | dictionary.Add(value,1);
45 | unOrderMap.Add(value,1);
46 | }
47 |
48 | using var mapEnumerator = unOrderMap.GetEnumerator();
49 | using var sortedDictionaryEnumerator = dictionary.GetEnumerator();
50 | while (sortedDictionaryEnumerator.MoveNext())
51 | {
52 | mapEnumerator.MoveNext();
53 | int key = sortedDictionaryEnumerator.Current.Key;
54 | mapEnumerator.Current.Key.Should().Be(key);
55 | }
56 | }
57 |
58 | [Fact]
59 | public void NativeCollectionClass()
60 | {
61 | UnOrderMap unOrderMap = new UnOrderMap();
62 | unOrderMap.IsDisposed.Should().Be(false);
63 | for (int i = 0; i < 100; i++)
64 | {
65 | unOrderMap.Add(Random.Shared.Next(),1);
66 | }
67 | unOrderMap.Dispose();
68 | unOrderMap.IsDisposed.Should().Be(true);
69 | unOrderMap.ReInit();
70 | unOrderMap.IsDisposed.Should().Be(false);
71 | unOrderMap.Count.Should().Be(0);
72 | for (int i = 0; i < 100; i++)
73 | {
74 | unOrderMap.Add(Random.Shared.Next(),1);
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/Queue.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace NativeCollection
5 | {
6 | public unsafe class Queue : INativeCollectionClass where T : unmanaged
7 | {
8 | private UnsafeType.Queue* _queue;
9 | private const int _defaultCapacity = 10;
10 | private int _capacity;
11 | public Queue(int capacity = 10)
12 | {
13 | _capacity = capacity;
14 | _queue = UnsafeType.Queue.Create(_capacity);
15 | IsDisposed = false;
16 | }
17 |
18 | public int Count => _queue->Count;
19 |
20 | public void Dispose()
21 | {
22 | if (IsDisposed)
23 | {
24 | return;
25 | }
26 | if (_queue != null)
27 | {
28 | _queue->Dispose();
29 | NativeMemoryHelper.Free(_queue);
30 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf>());
31 | IsDisposed = true;
32 | }
33 | }
34 |
35 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
36 | public void Clear()
37 | {
38 | _queue->Clear();
39 | }
40 |
41 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
42 | public void Enqueue(in T item)
43 | {
44 | _queue->Enqueue(item);
45 | }
46 |
47 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
48 | public T Dequeue()
49 | {
50 | return _queue->Dequeue();
51 | }
52 |
53 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
54 | public bool TryDequeue(out T result)
55 | {
56 | var value = _queue->TryDequeue(out result);
57 | return value;
58 | }
59 |
60 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
61 | public T Peek()
62 | {
63 | return _queue->Peek();
64 | }
65 |
66 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
67 | public bool TryPeek(out T result)
68 | {
69 | var value = _queue->TryPeek(out result);
70 | return value;
71 | }
72 |
73 | ~Queue()
74 | {
75 | Dispose();
76 | }
77 |
78 | public void ReInit()
79 | {
80 | if (IsDisposed)
81 | {
82 | _queue = UnsafeType.Queue.Create(_capacity);
83 | IsDisposed = false;
84 | }
85 | }
86 |
87 | public bool IsDisposed { get; private set; }
88 | }
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/HashSet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Runtime.CompilerServices;
5 |
6 | namespace NativeCollection
7 | {
8 | public unsafe class HashSet: ICollection, INativeCollectionClass where T : unmanaged, IEquatable
9 | {
10 |
11 | private UnsafeType.HashSet* _hashSet;
12 | private const int _defaultCapacity = 10;
13 | public HashSet(int capacity = _defaultCapacity)
14 | {
15 | _hashSet = UnsafeType.HashSet.Create(capacity);
16 | IsDisposed = false;
17 | }
18 | IEnumerator IEnumerable.GetEnumerator()
19 | {
20 | return GetEnumerator();
21 | }
22 |
23 | IEnumerator IEnumerable.GetEnumerator()
24 | {
25 | return GetEnumerator();
26 | }
27 |
28 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
29 | public UnsafeType.HashSet.Enumerator GetEnumerator() => new UnsafeType.HashSet.Enumerator(_hashSet);
30 |
31 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
32 | public void Add(T item)
33 | {
34 | _hashSet->Add(item);
35 | }
36 |
37 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
38 | public void Clear()
39 | {
40 | _hashSet->Clear();
41 | }
42 |
43 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
44 | public bool Contains(T item)
45 | {
46 | return _hashSet->Contains(item);
47 | }
48 |
49 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
50 | public void CopyTo(T[] array, int arrayIndex)
51 | {
52 | _hashSet->CopyTo(array, arrayIndex);
53 | }
54 |
55 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
56 | public bool Remove(T item)
57 | {
58 | return _hashSet->Remove(item);
59 | }
60 |
61 | public int Count => _hashSet->Count;
62 | public bool IsReadOnly => false;
63 |
64 | public void Dispose()
65 | {
66 | if (IsDisposed)
67 | {
68 | return;
69 | }
70 | if (_hashSet!=null)
71 | {
72 | _hashSet->Dispose();
73 | NativeMemoryHelper.Free(_hashSet);
74 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf>());
75 | IsDisposed = true;
76 | }
77 | }
78 |
79 | public void ReInit()
80 | {
81 | if (IsDisposed)
82 | {
83 | _hashSet = UnsafeType.HashSet.Create(_defaultCapacity);
84 | IsDisposed = false;
85 | }
86 | }
87 |
88 | public bool IsDisposed { get; private set; }
89 |
90 | ~HashSet()
91 | {
92 | Dispose();
93 | }
94 | }
95 | }
96 |
97 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection.Test/MapTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Xunit;
3 |
4 | namespace NativeCollection.Test;
5 |
6 | public class MapTest
7 | {
8 | [Fact]
9 | public void AddRemove()
10 | {
11 | Map map = new Map();
12 | map.Add(1,11);
13 | map.Count.Should().Be(1);
14 | map[1].Should().Be(11);
15 | map.Add(1,12);
16 | map.Count.Should().Be(1);
17 | map[1].Should().Be(11);
18 | map.Add(3,44);
19 | map.Count.Should().Be(2);
20 | map.Remove(3).Should().Be(true);
21 | map.Count.Should().Be(1);
22 | map.Clear();
23 | map.Count.Should().Be(0);
24 | map.Remove(1).Should().Be(false);
25 | map.Clear();
26 | for (int i = 0; i < 1000; i++)
27 | {
28 | map.Add(1,Random.Shared.Next());
29 | }
30 | map.Count.Should().Be(1);
31 |
32 | map.Clear();
33 | map.Add(1,100);
34 | map[1].Should().Be(100);
35 | map[1] = 101;
36 | map[1].Should().Be(101);
37 | map[2] = 102;
38 | map[2].Should().Be(102);
39 | SortedDictionary sortedDictionary = new SortedDictionary();
40 | sortedDictionary.Add(1,100);
41 | sortedDictionary[1] = 101;
42 | sortedDictionary[1].Should().Be(101);
43 | }
44 |
45 | [Fact]
46 | public void Enumerator()
47 | {
48 | SortedDictionary sortedDictionary = new SortedDictionary();
49 | Map map = new Map();
50 |
51 | for (int i = 0; i < 1000; i++)
52 | {
53 | int value = Random.Shared.Next();
54 | sortedDictionary.Add(value,1);
55 | map.Add(value,1);
56 | }
57 |
58 | using var mapEnumerator = map.GetEnumerator();
59 | using var sortedDictionaryEnumerator = sortedDictionary.GetEnumerator();
60 | while (sortedDictionaryEnumerator.MoveNext())
61 | {
62 | mapEnumerator.MoveNext();
63 | int key = sortedDictionaryEnumerator.Current.Key;
64 | mapEnumerator.Current.Key.Should().Be(key);
65 | }
66 | }
67 |
68 | [Fact]
69 | public void NativeCollectionClass()
70 | {
71 | Map map = new Map();
72 | map.IsDisposed.Should().Be(false);
73 | for (int i = 0; i < 100; i++)
74 | {
75 | map.Add(Random.Shared.Next(),1);
76 | }
77 | map.Dispose();
78 | map.IsDisposed.Should().Be(true);
79 | map.ReInit();
80 | map.IsDisposed.Should().Be(false);
81 | map.Count.Should().Be(0);
82 | for (int i = 0; i < 100; i++)
83 | {
84 | map.Add(Random.Shared.Next(),1);
85 | }
86 | }
87 |
88 | }
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/Map.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Runtime.CompilerServices;
5 | using NativeCollection.UnsafeType;
6 |
7 | namespace NativeCollection
8 | {
9 | public unsafe class Map : IEnumerable>, INativeCollectionClass
10 | where T : unmanaged, IEquatable, IComparable where K : unmanaged, IEquatable
11 | {
12 | private const int _defaultPoolBlockSize = 64;
13 | private int _poolBlockSize;
14 | private UnsafeType.Map* _map;
15 |
16 | public Map(int poolBlockSize = _defaultPoolBlockSize)
17 | {
18 | _poolBlockSize = poolBlockSize;
19 | _map = UnsafeType.Map.Create(_poolBlockSize);
20 | IsDisposed = false;
21 | }
22 |
23 | public K this[T key]
24 | {
25 | get => (*_map)[key];
26 | set => (*_map)[key] = value;
27 | }
28 |
29 | public int Count => _map->Count;
30 |
31 | IEnumerator> IEnumerable>.GetEnumerator()
32 | {
33 | return GetEnumerator();
34 | }
35 |
36 | IEnumerator IEnumerable.GetEnumerator()
37 | {
38 | return GetEnumerator();
39 | }
40 |
41 | public void Dispose()
42 | {
43 | if (IsDisposed) return;
44 | if (_map != null)
45 | {
46 | _map->Dispose();
47 | NativeMemoryHelper.Free(_map);
48 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf>());
49 | IsDisposed = true;
50 | }
51 | }
52 |
53 | public void ReInit()
54 | {
55 | if (IsDisposed)
56 | {
57 | _map = UnsafeType.Map.Create(_poolBlockSize);
58 | IsDisposed = false;
59 | }
60 | }
61 |
62 | public bool IsDisposed { get; private set; }
63 |
64 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
65 | public void Add(T key, K value)
66 | {
67 | _map->Add(key, value);
68 | }
69 |
70 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
71 | public bool Remove(T key)
72 | {
73 | return _map->Remove(key);
74 | }
75 |
76 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
77 | public void Clear()
78 | {
79 | _map->Clear();
80 | }
81 |
82 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
83 | public UnsafeType.SortedSet>.Enumerator GetEnumerator()
84 | {
85 | return _map->GetEnumerator();
86 | }
87 |
88 | ~Map()
89 | {
90 | Dispose();
91 | }
92 | }
93 | }
94 |
95 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/SortedSet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Runtime.CompilerServices;
5 |
6 | namespace NativeCollection
7 | {
8 | public unsafe class SortedSet : ICollection, INativeCollectionClass where T : unmanaged, IEquatable,IComparable
9 | {
10 | private UnsafeType.SortedSet* _sortedSet;
11 | private const int _defaultNodePoolBlockSize = 64;
12 | private int _poolBlockSize;
13 | public SortedSet(int nodePoolSize = _defaultNodePoolBlockSize)
14 | {
15 | _poolBlockSize = nodePoolSize;
16 | _sortedSet = UnsafeType.SortedSet.Create(_poolBlockSize);
17 | IsDisposed = false;
18 | }
19 | IEnumerator IEnumerable.GetEnumerator()
20 | {
21 | return GetEnumerator();
22 | }
23 |
24 | IEnumerator IEnumerable.GetEnumerator()
25 | {
26 | return GetEnumerator();
27 | }
28 |
29 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
30 | public UnsafeType.SortedSet.Enumerator GetEnumerator()
31 | {
32 | return new UnsafeType.SortedSet.Enumerator(_sortedSet);
33 | }
34 |
35 | void ICollection.Add(T item)
36 | {
37 | _sortedSet->Add(item);
38 | }
39 |
40 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
41 | public bool Add(T item)
42 | {
43 | return _sortedSet->Add(item);
44 | }
45 |
46 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
47 | public void Clear()
48 | {
49 | _sortedSet->Clear();
50 | }
51 |
52 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
53 | public bool Contains(T item)
54 | {
55 | return _sortedSet->Contains(item);
56 | }
57 |
58 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
59 | public void CopyTo(T[] array, int arrayIndex)
60 | {
61 | _sortedSet->CopyTo(array,arrayIndex);
62 | }
63 |
64 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
65 | public bool Remove(T item)
66 | {
67 | return _sortedSet->Remove(item);
68 | }
69 |
70 | public T? Min => _sortedSet->Min;
71 |
72 | public T? Max => _sortedSet->Max;
73 |
74 | public int Count => _sortedSet->Count;
75 | public bool IsReadOnly => false;
76 | public void Dispose()
77 | {
78 | if (IsDisposed)
79 | {
80 | return;
81 | }
82 | if (_sortedSet!=null)
83 | {
84 | _sortedSet->Dispose();
85 | NativeMemoryHelper.Free(_sortedSet);
86 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf>());
87 | IsDisposed = true;
88 | }
89 | }
90 |
91 | public void ReInit()
92 | {
93 | if (IsDisposed)
94 | {
95 | _sortedSet = UnsafeType.SortedSet.Create(_poolBlockSize);
96 | IsDisposed = false;
97 | }
98 | }
99 |
100 | public bool IsDisposed { get; private set; }
101 | }
102 | }
103 |
104 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeCollection", "NativeCollection\NativeCollection.csproj", "{905BB42C-1200-4233-9236-B83E966E29B7}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmark", "Benchmark\Benchmark.csproj", "{3A5D66D6-2B33-4E99-86C2-92248472758C}"
6 | EndProject
7 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5AE8E136-E26F-4D78-A185-3A7C17A06531}"
8 | EndProject
9 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{51879ABF-A076-4EBB-9B55-814F5EF1F571}"
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeCollection.Test", "NativeCollection.Test\NativeCollection.Test.csproj", "{9AAD09E7-B5FB-4715-A23D-519F0F7D8B61}"
12 | EndProject
13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandbox", "sandbox", "{0408D84C-B09D-4325-9031-2634446A0BFB}"
14 | EndProject
15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MemoryProfile", "MemoryProfile\MemoryProfile.csproj", "{4291EA34-4635-4EA5-8982-369707D3D8F4}"
16 | EndProject
17 | Global
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Release|Any CPU = Release|Any CPU
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {905BB42C-1200-4233-9236-B83E966E29B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {905BB42C-1200-4233-9236-B83E966E29B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {905BB42C-1200-4233-9236-B83E966E29B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {905BB42C-1200-4233-9236-B83E966E29B7}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {3A5D66D6-2B33-4E99-86C2-92248472758C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {3A5D66D6-2B33-4E99-86C2-92248472758C}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {3A5D66D6-2B33-4E99-86C2-92248472758C}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {3A5D66D6-2B33-4E99-86C2-92248472758C}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {9AAD09E7-B5FB-4715-A23D-519F0F7D8B61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {9AAD09E7-B5FB-4715-A23D-519F0F7D8B61}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {9AAD09E7-B5FB-4715-A23D-519F0F7D8B61}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {9AAD09E7-B5FB-4715-A23D-519F0F7D8B61}.Release|Any CPU.Build.0 = Release|Any CPU
35 | {4291EA34-4635-4EA5-8982-369707D3D8F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {4291EA34-4635-4EA5-8982-369707D3D8F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {4291EA34-4635-4EA5-8982-369707D3D8F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {4291EA34-4635-4EA5-8982-369707D3D8F4}.Release|Any CPU.Build.0 = Release|Any CPU
39 | EndGlobalSection
40 | GlobalSection(NestedProjects) = preSolution
41 | {905BB42C-1200-4233-9236-B83E966E29B7} = {5AE8E136-E26F-4D78-A185-3A7C17A06531}
42 | {9AAD09E7-B5FB-4715-A23D-519F0F7D8B61} = {51879ABF-A076-4EBB-9B55-814F5EF1F571}
43 | {3A5D66D6-2B33-4E99-86C2-92248472758C} = {0408D84C-B09D-4325-9031-2634446A0BFB}
44 | {4291EA34-4635-4EA5-8982-369707D3D8F4} = {51879ABF-A076-4EBB-9B55-814F5EF1F571}
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection.Test/QueueTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Xunit;
3 |
4 | namespace NativeCollection.Test;
5 |
6 | public class QueueTest
7 | {
8 | [Fact]
9 | public void EnqueueDequeue()
10 | {
11 | System.Collections.Generic.Queue managedQueue = new System.Collections.Generic.Queue();
12 | Queue nativeQueue = new Queue();
13 |
14 | for (int i = 0; i < 1000; i++)
15 | {
16 | int value = Random.Shared.Next();
17 | managedQueue.Enqueue(value);
18 | nativeQueue.Enqueue(value);
19 | nativeQueue.Count.Should().Be(i + 1);
20 | }
21 |
22 | for (int i = 0; i < 1000; i++)
23 | {
24 | managedQueue.Dequeue().Should().Be(nativeQueue.Dequeue());
25 | nativeQueue.Count.Should().Be(1000 - i - 1);
26 | }
27 |
28 | bool hasException = false;
29 |
30 | try
31 | {
32 | nativeQueue.Dequeue();
33 | }
34 | catch (Exception e)
35 | {
36 | hasException = true;
37 | }
38 |
39 | hasException.Should().Be(true);
40 | }
41 |
42 | [Fact]
43 | public void Peak()
44 | {
45 | Queue nativeQueue = new Queue();
46 | System.Collections.Generic.Queue managedQueue = new System.Collections.Generic.Queue();
47 |
48 | for (int i = 0; i < 1000; i++)
49 | {
50 | int value = Random.Shared.Next();
51 | managedQueue.Enqueue(value);
52 | nativeQueue.Enqueue(value);
53 | nativeQueue.Peek().Should().Be(managedQueue.Peek());
54 | nativeQueue.TryPeek(out var peakValue);
55 | managedQueue.TryPeek(out var peakValue2);
56 | peakValue.Should().Be(peakValue2);
57 | }
58 |
59 | {
60 | nativeQueue.Clear();
61 | nativeQueue.TryPeek(out var value).Should().Be(false);
62 | }
63 |
64 |
65 | }
66 |
67 | [Fact]
68 | public void Clear()
69 | {
70 | Queue nativeQueue = new Queue();
71 | for (int i = 0; i < 100; i++)
72 | {
73 | for (int j = 0; j < Random.Shared.Next(1,100); j++)
74 | {
75 | int value = Random.Shared.Next();
76 | nativeQueue.Enqueue(value);
77 | }
78 | nativeQueue.Clear();
79 | nativeQueue.Count.Should().Be(0);
80 | }
81 | }
82 |
83 | [Fact]
84 | public void NativeCollectionClass()
85 | {
86 | Queue queue = new Queue();
87 | queue.IsDisposed.Should().Be(false);
88 | for (int i = 0; i < 100; i++)
89 | {
90 | queue.Enqueue(Random.Shared.Next());
91 | }
92 | queue.Dispose();
93 | queue.IsDisposed.Should().Be(true);
94 | queue.ReInit();
95 | queue.IsDisposed.Should().Be(false);
96 | queue.Count.Should().Be(0);
97 | for (int i = 0; i < 100; i++)
98 | {
99 | queue.Enqueue(Random.Shared.Next());
100 | }
101 | }
102 | }
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/MultiMap.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Runtime.CompilerServices;
5 | using NativeCollection.UnsafeType;
6 |
7 | namespace NativeCollection
8 | {
9 | public unsafe class MultiMap : IEnumerable>, INativeCollectionClass
10 | where T : unmanaged, IEquatable, IComparable where K : unmanaged, IEquatable
11 | {
12 | private UnsafeType.MultiMap* _multiMap;
13 |
14 | private const int _defaultPoolBlockSize = 64;
15 |
16 | private const int _defaultListPoolSize = 200;
17 |
18 | private int _poolBlockSize;
19 |
20 | private int _listPoolSize;
21 |
22 | public MultiMap(int listPoolSize = _defaultListPoolSize,int nodePoolBlockSize = _defaultPoolBlockSize)
23 | {
24 | _poolBlockSize = nodePoolBlockSize;
25 | _listPoolSize = listPoolSize;
26 | _multiMap = UnsafeType.MultiMap.Create(_poolBlockSize,_listPoolSize);
27 | IsDisposed = false;
28 | }
29 |
30 | public Span this[T key] => (*_multiMap)[key];
31 |
32 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 | public void Add(T key, K value)
34 | {
35 | _multiMap->Add(key,value);
36 | }
37 |
38 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 | public bool Remove(T key, K value)
40 | {
41 | return _multiMap->Remove(key, value);
42 | }
43 |
44 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 | public bool Remove(T key)
46 | {
47 | return _multiMap->Remove(key);
48 | }
49 |
50 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 | public void Clear()
52 | {
53 | _multiMap->Clear();
54 | }
55 |
56 | public int Count => _multiMap->Count;
57 |
58 | IEnumerator> IEnumerable>. GetEnumerator()
59 | {
60 | return GetEnumerator();
61 | }
62 |
63 | IEnumerator IEnumerable.GetEnumerator()
64 | {
65 | return GetEnumerator();
66 | }
67 |
68 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
69 | public UnsafeType.SortedSet>.Enumerator GetEnumerator()
70 | {
71 | return _multiMap->GetEnumerator();
72 | }
73 |
74 | public void Dispose()
75 | {
76 | if (IsDisposed)
77 | {
78 | return;
79 | }
80 |
81 | if (_multiMap!=null)
82 | {
83 |
84 | _multiMap->Dispose();
85 | NativeMemoryHelper.Free(_multiMap);
86 | NativeMemoryHelper.RemoveNativeMemoryByte(Unsafe.SizeOf>());
87 | IsDisposed = true;
88 | }
89 | }
90 |
91 | public void ReInit()
92 | {
93 | if (IsDisposed)
94 | {
95 | _multiMap = UnsafeType.MultiMap.Create(_poolBlockSize,_listPoolSize);
96 | IsDisposed = false;
97 | }
98 | }
99 |
100 | public bool IsDisposed { get; private set; }
101 |
102 | ~MultiMap()
103 | {
104 | Dispose();
105 | }
106 | }
107 | }
108 |
109 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/ThrowHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace NativeCollection
5 | {
6 | internal static class ThrowHelper
7 | {
8 | [DoesNotReturn]
9 | public static void StackInitialCapacityException()
10 | {
11 | throw new ArgumentOutOfRangeException();
12 | }
13 |
14 | [DoesNotReturn]
15 | public static void StackEmptyException()
16 | {
17 | throw new InvalidOperationException("Stack Empty");
18 | }
19 |
20 | [DoesNotReturn]
21 | public static void QueueEmptyException()
22 | {
23 | throw new InvalidOperationException("EmptyQueue");
24 | }
25 |
26 | [DoesNotReturn]
27 | public static void ListInitialCapacityException()
28 | {
29 | throw new ArgumentOutOfRangeException();
30 | }
31 |
32 | [DoesNotReturn]
33 | public static void IndexMustBeLessException()
34 | {
35 | throw new ArgumentOutOfRangeException("IndexMustBeLess");
36 | }
37 |
38 |
39 | [DoesNotReturn]
40 | public static void ListSmallCapacity()
41 | {
42 | throw new ArgumentOutOfRangeException("SmallCapacity");
43 | }
44 |
45 |
46 | [DoesNotReturn]
47 | public static void ListIndexOutOfRange()
48 | {
49 | throw new ArgumentOutOfRangeException("ListIndexOutOfRange");
50 | }
51 |
52 | [DoesNotReturn]
53 | public static void ArgumentNullException(string argName)
54 | {
55 | throw new ArgumentNullException(argName);
56 | }
57 | [DoesNotReturn]
58 | public static void ArgumentOutOfRangeException(string argName)
59 | {
60 | throw new ArgumentOutOfRangeException(argName);
61 | }
62 |
63 | [DoesNotReturn]
64 | public static void ConcurrentOperationsNotSupported()
65 | {
66 | throw new InvalidOperationException("ConcurrentOperationsNotSupported");
67 | }
68 |
69 | [DoesNotReturn]
70 | public static void HashSetCapacityOutOfRange()
71 | {
72 | throw new ArgumentOutOfRangeException("HashSetCapacityOutOfRange");
73 | }
74 |
75 | [DoesNotReturn]
76 | public static void HashSetEnumFailedVersion()
77 | {
78 | throw new InvalidOperationException("EnumFailedVersion");
79 | }
80 |
81 | [DoesNotReturn]
82 | public static void HashSetEnumOpCantHappen()
83 | {
84 | throw new InvalidOperationException("EnumOpCantHappen");
85 | }
86 |
87 | [DoesNotReturn]
88 | public static void SortedSetVersionChanged()
89 | {
90 | throw new InvalidOperationException("_version != _tree.version");
91 | }
92 |
93 | [DoesNotReturn]
94 | public static void ThrowAddingDuplicateWithKeyArgumentException()
95 | {
96 | throw new ArgumentException("AddingDuplicateWithKey");
97 | }
98 | }
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/UnsafeType/HashHelpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NativeCollection.UnsafeType
4 | {
5 | public static class HashHelpers
6 | {
7 | public const uint HashCollisionThreshold = 100;
8 |
9 | // This is the maximum prime smaller than Array.MaxLength.
10 | public const int MaxPrimeArrayLength = 0x7FFFFFC3;
11 |
12 | public const int HashPrime = 101;
13 |
14 | private static readonly int[] s_primes = new int[72]
15 | {
16 | 3,
17 | 7,
18 | 11,
19 | 17,
20 | 23,
21 | 29,
22 | 37,
23 | 47,
24 | 59,
25 | 71,
26 | 89,
27 | 107,
28 | 131,
29 | 163,
30 | 197,
31 | 239,
32 | 293,
33 | 353,
34 | 431,
35 | 521,
36 | 631,
37 | 761,
38 | 919,
39 | 1103,
40 | 1327,
41 | 1597,
42 | 1931,
43 | 2333,
44 | 2801,
45 | 3371,
46 | 4049,
47 | 4861,
48 | 5839,
49 | 7013,
50 | 8419,
51 | 10103,
52 | 12143,
53 | 14591,
54 | 17519,
55 | 21023,
56 | 25229,
57 | 30293,
58 | 36353,
59 | 43627,
60 | 52361,
61 | 62851,
62 | 75431,
63 | 90523,
64 | 108631,
65 | 130363,
66 | 156437,
67 | 187751,
68 | 225307,
69 | 270371,
70 | 324449,
71 | 389357,
72 | 467237,
73 | 560689,
74 | 672827,
75 | 807403,
76 | 968897,
77 | 1162687,
78 | 1395263,
79 | 1674319,
80 | 2009191,
81 | 2411033,
82 | 2893249,
83 | 3471899,
84 | 4166287,
85 | 4999559,
86 | 5999471,
87 | 7199369
88 | };
89 |
90 | public static bool IsPrime(int candidate)
91 | {
92 | if ((candidate & 1) == 0)
93 | return candidate == 2;
94 | int num = (int) Math.Sqrt((double) candidate);
95 | for (int index = 3; index <= num; index += 2)
96 | {
97 | if (candidate % index == 0)
98 | return false;
99 | }
100 | return true;
101 | }
102 |
103 | public static int GetPrime(int min)
104 | {
105 | if (min < 0)
106 | throw new ArgumentException("SR.Arg_HTCapacityOverflow");
107 | foreach (int prime in HashHelpers.s_primes)
108 | {
109 | if (prime >= min)
110 | return prime;
111 | }
112 | for (int candidate = min | 1; candidate < int.MaxValue; candidate += 2)
113 | {
114 | if (HashHelpers.IsPrime(candidate) && (candidate - 1) % 101 != 0)
115 | return candidate;
116 | }
117 | return min;
118 | }
119 |
120 | public static int ExpandPrime(int oldSize)
121 | {
122 | int min = 2 * oldSize;
123 | return (uint) min > 2147483587U && 2147483587 > oldSize ? 2147483587 : HashHelpers.GetPrime(min);
124 | }
125 |
126 | /// Returns approximate reciprocal of the divisor: ceil(2**64 / divisor).
127 | /// This should only be used on 64-bit.
128 | public static ulong GetFastModMultiplier(uint divisor) =>
129 | ulong.MaxValue / divisor + 1;
130 |
131 | }
132 | }
133 |
134 |
--------------------------------------------------------------------------------
/NativeCollection/Benchmark/Benchmarks/BenchmarkHashSet.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using BenchmarkDotNet.Configs;
3 |
4 | namespace Benchmark.Benchmarks;
5 | [ShortRunJob]
6 | [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
7 | [CategoriesColumn]
8 | public class BenchmarkHashSet
9 | {
10 | [Params(10000,100000,1000000)]
11 | public int Count { get; set; }
12 | private List input;
13 | private NativeCollection.HashSet nativesHashSet;
14 | private HashSet managedHashSet;
15 |
16 |
17 | [GlobalSetup(Targets = new []{nameof(NativeAddRemove),nameof(ManagedAddRemove)})]
18 | public void InitAddRemove()
19 | {
20 | nativesHashSet = new NativeCollection.HashSet(1000);
21 | managedHashSet = new HashSet();
22 | input = new List();
23 | for (int i = 0; i < Count; i++)
24 | {
25 | input.Add(Random.Shared.Next(Count));
26 | }
27 | foreach (var value in input)
28 | {
29 | nativesHashSet.Add(value);
30 | }
31 | foreach (var value in input)
32 | {
33 | managedHashSet.Add(value);
34 | }
35 | }
36 |
37 | [BenchmarkCategory("AddRemove")]
38 | [Benchmark]
39 | public void NativeAddRemove()
40 | {
41 | for (int i = 0; i < 100; i++)
42 | {
43 | for (int j = Count; j < Count+1000; j++)
44 | {
45 | nativesHashSet.Add(j);
46 | }
47 |
48 | for (int j = Count; j < Count+1000; j++)
49 | {
50 | nativesHashSet.Remove(j);
51 | }
52 | }
53 | }
54 |
55 | [BenchmarkCategory("AddRemove")]
56 | [Benchmark(Baseline = true)]
57 | public void ManagedAddRemove()
58 | {
59 | for (int i = 0; i < 100; i++)
60 | {
61 | for (int j = Count; j < Count+1000; j++)
62 | {
63 | managedHashSet.Add(j);
64 | }
65 |
66 | for (int j = Count; j < Count+1000; j++)
67 | {
68 | managedHashSet.Remove(j);
69 | }
70 | }
71 | }
72 |
73 | [GlobalSetup(Targets = new []{nameof(NativeEnumerate),nameof(ManagedEnumerate)})]
74 | public void InitEnumerate()
75 | {
76 | nativesHashSet = new NativeCollection.HashSet();
77 | managedHashSet = new HashSet();
78 | input = new List();
79 | for (int i = 0; i < Count; i++)
80 | {
81 | input.Add(Random.Shared.Next());
82 | }
83 | foreach (var value in input)
84 | {
85 | nativesHashSet.Add(value);
86 | }
87 | foreach (var value in input)
88 | {
89 | managedHashSet.Add(value);
90 | }
91 | }
92 |
93 | [BenchmarkCategory("Enumerate")]
94 | [Benchmark]
95 | public void NativeEnumerate()
96 | {
97 | int result = 0;
98 | foreach (var value in nativesHashSet)
99 | {
100 | result += value;
101 | }
102 | }
103 |
104 | [BenchmarkCategory("Enumerate")]
105 | [Benchmark(Baseline = true)]
106 | public void ManagedEnumerate()
107 | {
108 | int result = 0;
109 | foreach (var value in managedHashSet)
110 | {
111 | result += value;
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/NativeMemoryHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 |
6 | namespace NativeCollection
7 | {
8 | public static unsafe class NativeMemoryHelper
9 | {
10 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
11 | public static void* Alloc(UIntPtr byteCount)
12 | {
13 | AddNativeMemoryByte((long)byteCount);
14 | #if NET6_0_OR_GREATER
15 | return NativeMemory.Alloc(byteCount);
16 | #else
17 | return Marshal.AllocHGlobal((int)byteCount).ToPointer();
18 | #endif
19 | }
20 |
21 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
22 | public static void* Alloc(UIntPtr elementCount, UIntPtr elementSize)
23 | {
24 | AddNativeMemoryByte((long)((long)elementCount * (long)elementSize));
25 | #if NET6_0_OR_GREATER
26 | return NativeMemory.Alloc(elementCount, elementSize);
27 | #else
28 | return Marshal.AllocHGlobal((int)((int)elementCount*(int)elementSize)).ToPointer();
29 | #endif
30 | }
31 |
32 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 | public static void* AllocZeroed(UIntPtr byteCount)
34 | {
35 | AddNativeMemoryByte((long)byteCount);
36 | #if NET6_0_OR_GREATER
37 | return NativeMemory.AllocZeroed(byteCount);
38 | #else
39 | var ptr = Marshal.AllocHGlobal((int)byteCount).ToPointer();
40 | Unsafe.InitBlockUnaligned(ptr,0,(uint)byteCount);
41 | return ptr;
42 | #endif
43 | }
44 |
45 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
46 | public static void* AllocZeroed(UIntPtr elementCount, UIntPtr elementSize)
47 | {
48 | AddNativeMemoryByte((long)((long)elementCount * (long)elementSize));
49 | #if NET6_0_OR_GREATER
50 | return NativeMemory.AllocZeroed(elementCount, elementSize);
51 | #else
52 | var ptr = Marshal.AllocHGlobal((int)((int)elementCount*(int)elementSize)).ToPointer();
53 | Unsafe.InitBlockUnaligned(ptr,0,(uint)((uint)elementCount*(uint)elementSize));
54 | return ptr;
55 | #endif
56 | }
57 |
58 |
59 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
60 | public static void Free(T* ptr) where T : unmanaged
61 | {
62 | #if NET6_0_OR_GREATER
63 | NativeMemory.Free(ptr);
64 | #else
65 | Marshal.FreeHGlobal(new IntPtr(ptr));
66 | #endif
67 | }
68 |
69 | #if MEMORY_PROFILE
70 | public static long NativeMemoryBytes;
71 | #endif
72 |
73 | public static void AddNativeMemoryByte(long size)
74 | {
75 | GC.AddMemoryPressure((long)size);
76 | //Console.WriteLine($"AddNativeMemoryByte {size}");
77 | #if MEMORY_PROFILE
78 | NativeMemoryBytes += size;
79 | #endif
80 | }
81 |
82 | public static void RemoveNativeMemoryByte(long size)
83 | {
84 | GC.RemoveMemoryPressure(size);
85 | //Console.WriteLine($"RemoveMemoryPressure {size}");
86 | #if MEMORY_PROFILE
87 | NativeMemoryBytes -= size;
88 | #endif
89 | }
90 |
91 | public static long GetNativeMemoryBytes()
92 | {
93 | #if MEMORY_PROFILE
94 | return NativeMemoryBytes;
95 | #else
96 | return 0;
97 | #endif
98 | }
99 | }
100 | }
101 |
102 |
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection.Test/HashSetTest.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Xunit;
3 | using Xunit.Sdk;
4 |
5 | namespace NativeCollection.Test;
6 |
7 | public class HashSetTest
8 | {
9 | [Fact]
10 | public void AddRemove()
11 | {
12 | HashSet hashSet = new HashSet();
13 | hashSet.Add(1);
14 | hashSet.Add(2);
15 | hashSet.Add(1);
16 | hashSet.Count.Should().Be(2);
17 | hashSet.Remove(2);
18 | hashSet.Count.Should().Be(1);
19 | hashSet.Remove(1);
20 | hashSet.Count.Should().Be(0);
21 | hashSet.Add(23);
22 | hashSet.Add(123);
23 | hashSet.Clear();
24 | hashSet.Count.Should().Be(0);
25 | hashSet.Remove(1).Should().Be(false);
26 | hashSet.Add(1);
27 | hashSet.Remove(1).Should().Be(true);
28 | }
29 |
30 | [Fact]
31 | public void Contains()
32 | {
33 | HashSet hashSet = new HashSet();
34 | hashSet.Contains(1).Should().Be(false);
35 | hashSet.Add(1);
36 | hashSet.Contains(1).Should().Be(true);
37 | hashSet.Contains(2).Should().Be(false);
38 | hashSet.Clear();
39 | hashSet.Contains(1).Should().Be(false);
40 | }
41 |
42 | [Fact]
43 | public void AddRemoveInEnumerator()
44 | {
45 | HashSet hashSet = new HashSet();
46 |
47 | for (int i = 0; i < 100; i++)
48 | {
49 | int value = i;
50 | hashSet.Add(value);
51 | }
52 |
53 | foreach (var value in hashSet)
54 | {
55 | if (value%2==0)
56 | {
57 | hashSet.Remove(value);
58 | }
59 | }
60 |
61 | hashSet.Count.Should().Be(50);
62 | hashSet.Clear();
63 |
64 | for (int i = 0; i < 100; i++)
65 | {
66 | int value = Random.Shared.Next();
67 | hashSet.Add(value);
68 | }
69 |
70 | bool hasException = false;
71 |
72 | try
73 | {
74 | foreach (var value in hashSet)
75 | {
76 | hashSet.Add(Random.Shared.Next());
77 | }
78 | }
79 | catch (Exception e)
80 | {
81 | hasException = true;
82 | }
83 |
84 | hasException.Should().Be(true);
85 | hasException = false;
86 |
87 |
88 | }
89 |
90 | [Fact]
91 | public void CopyTo()
92 | {
93 | int[] rawList = new int[100];
94 | HashSet hashSet = new HashSet();
95 | for (int i = 0; i < 100; i++)
96 | {
97 | hashSet.Add(i);
98 | }
99 |
100 | hashSet.CopyTo(rawList,0);
101 |
102 | for (int i = 0; i < 100; i++)
103 | {
104 | rawList[i].Should().Be(i);
105 | }
106 |
107 | }
108 |
109 | [Fact]
110 | public void NativeCollectionClass()
111 | {
112 | HashSet hashSet = new HashSet();
113 | hashSet.IsDisposed.Should().Be(false);
114 | for (int i = 0; i < 100; i++)
115 | {
116 | hashSet.Add(Random.Shared.Next());
117 | }
118 | hashSet.Dispose();
119 | hashSet.IsDisposed.Should().Be(true);
120 | hashSet.ReInit();
121 | hashSet.IsDisposed.Should().Be(false);
122 | hashSet.Count.Should().Be(0);
123 | for (int i = 0; i < 100; i++)
124 | {
125 | hashSet.Add(Random.Shared.Next());
126 | }
127 | }
128 | }
--------------------------------------------------------------------------------
/NativeCollection/NativeCollection/UnsafeType/Map/Map.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.InteropServices;
6 |
7 | namespace NativeCollection.UnsafeType
8 | {
9 | public unsafe struct Map :IEnumerable>, IDisposable where T : unmanaged, IEquatable, IComparable where K : unmanaged, IEquatable
10 | {
11 | private UnsafeType.SortedSet>* _sortedSet;
12 |
13 | public static Map* Create(int poolBlockSize)
14 | {
15 | Map* map = (Map*)NativeMemoryHelper.Alloc((UIntPtr)Unsafe.SizeOf