Skip to content

Commit fd5f935

Browse files
author
LoneWandererProductions
committed
add a new test object
1 parent b588764 commit fd5f935

2 files changed

Lines changed: 156 additions & 0 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace ExtendedSystemObjects
2+
{
3+
using System.Runtime.InteropServices;
4+
5+
public unsafe partial struct UnmanagedIntMap
6+
{
7+
[StructLayout(LayoutKind.Sequential)]
8+
internal struct Entry
9+
{
10+
public int Key;
11+
public int Value;
12+
public byte Used;
13+
}
14+
}
15+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
using System;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
namespace ExtendedSystemObjects
6+
{
7+
8+
public unsafe partial struct UnmanagedIntMap
9+
{
10+
private const int INVALID = -1;
11+
12+
private Entry* _entries;
13+
private int _capacity;
14+
private int _count;
15+
16+
public int Count => _count;
17+
18+
public void Init(int capacityPowerOf2 = 8)
19+
{
20+
_capacity = 1 << capacityPowerOf2; // must be power of 2
21+
int size = sizeof(Entry) * _capacity;
22+
_entries = (Entry*)Marshal.AllocHGlobal(size);
23+
Unsafe.InitBlock(_entries, 0, (uint)size);
24+
_count = 0;
25+
}
26+
27+
public void Set(int key, int value)
28+
{
29+
if (_count >= (_capacity * 0.7f))
30+
Resize();
31+
32+
int mask = _capacity - 1;
33+
int index = key & mask;
34+
35+
for (int i = 0; i < _capacity; i++)
36+
{
37+
ref Entry slot = ref _entries[(index + i) & mask];
38+
if (slot.Used == 0 || slot.Key == key)
39+
{
40+
slot.Key = key;
41+
slot.Value = value;
42+
slot.Used = 1;
43+
_count++;
44+
return;
45+
}
46+
}
47+
48+
throw new InvalidOperationException("UnmanagedIntMap full");
49+
}
50+
51+
public bool ContainsKey(int key)
52+
{
53+
int mask = _capacity - 1;
54+
int index = key & mask;
55+
56+
for (int i = 0; i < _capacity; i++)
57+
{
58+
ref Entry slot = ref _entries[(index + i) & mask];
59+
if (slot.Used == 0) break;
60+
if (slot.Key == key)
61+
return true;
62+
}
63+
64+
return false;
65+
}
66+
67+
public bool TryGet(int key, out int value)
68+
{
69+
int mask = _capacity - 1;
70+
int index = key & mask;
71+
72+
for (int i = 0; i < _capacity; i++)
73+
{
74+
ref Entry slot = ref _entries[(index + i) & mask];
75+
if (slot.Used == 0) break;
76+
if (slot.Key == key)
77+
{
78+
value = slot.Value;
79+
return true;
80+
}
81+
}
82+
83+
value = INVALID;
84+
return false;
85+
}
86+
87+
public bool TryRemove(int key)
88+
{
89+
int mask = _capacity - 1;
90+
int index = key & mask;
91+
92+
for (int i = 0; i < _capacity; i++)
93+
{
94+
ref Entry slot = ref _entries[(index + i) & mask];
95+
if (slot.Used == 0) break;
96+
if (slot.Key == key)
97+
{
98+
slot.Used = 0;
99+
slot.Key = INVALID;
100+
slot.Value = INVALID;
101+
_count--;
102+
return true;
103+
}
104+
}
105+
106+
return false;
107+
}
108+
109+
public void Free()
110+
{
111+
if (_entries != null)
112+
{
113+
Marshal.FreeHGlobal((IntPtr)_entries);
114+
_entries = null;
115+
}
116+
117+
_capacity = 0;
118+
_count = 0;
119+
}
120+
121+
public void Resize()
122+
{
123+
int newCapacity = _capacity * 2;
124+
var newMap = new UnmanagedIntMap();
125+
126+
newMap.Init((int)Math.Log2(newCapacity)); // power-of-2
127+
128+
for (int i = 0; i < _capacity; i++)
129+
{
130+
ref var entry = ref _entries[i];
131+
if (entry.Used == 1)
132+
newMap.Set(entry.Key, entry.Value);
133+
}
134+
135+
Free(); // free old buffer
136+
_entries = newMap._entries;
137+
_capacity = newMap._capacity;
138+
_count = newMap._count;
139+
}
140+
}
141+
}

0 commit comments

Comments
 (0)