Skip to content

Commit f865df6

Browse files
author
LoneWandererProductions
committed
add a new lookup map
1 parent ceda970 commit f865df6

6 files changed

Lines changed: 161 additions & 11 deletions

File tree

0 Bytes
Loading
0 Bytes
Loading
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace ExtendedSystemObjects.Helper
2+
{
3+
internal static class SharedResources
4+
{
5+
/// <summary>
6+
/// The small primes
7+
/// </summary>
8+
internal static readonly int[] SmallPrimes =
9+
{
10+
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
11+
103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199
12+
};
13+
}
14+
}

ExtendedSystemObjects/ImmutableLookupMap.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using System.Collections;
1414
using System.Collections.Generic;
1515
using System.Runtime.CompilerServices;
16+
using ExtendedSystemObjects.Helper;
1617

1718
namespace ExtendedSystemObjects
1819
{
@@ -23,15 +24,6 @@ namespace ExtendedSystemObjects
2324
public sealed class ImmutableLookupMap<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
2425
where TKey : struct, IEquatable<TKey>
2526
{
26-
/// <summary>
27-
/// The small primes
28-
/// </summary>
29-
private static readonly int[] SmallPrimes =
30-
{
31-
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
32-
103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199
33-
};
34-
3527
/// <summary>
3628
/// The key presence
3729
/// </summary>
@@ -219,7 +211,7 @@ private static bool IsPrime(int number)
219211
return false;
220212
}
221213

222-
foreach (var prime in SmallPrimes)
214+
foreach (var prime in SharedResources.SmallPrimes)
223215
{
224216
if (number == prime)
225217
{
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Runtime.CompilerServices;
5+
using ExtendedSystemObjects.Helper;
6+
using ExtendedSystemObjects.Interfaces;
7+
8+
namespace ExtendedSystemObjects
9+
{
10+
/// <summary>
11+
/// A high-performance, immutable lookup map using unmanaged arrays.
12+
/// </summary>
13+
public sealed unsafe class ImmutableLookupMapUnmanaged<TKey, TValue> : IDisposable, IEnumerable<KeyValuePair<TKey, TValue>>
14+
where TKey : unmanaged, IEquatable<TKey>
15+
where TValue : unmanaged
16+
{
17+
private readonly UnmanagedArray<TKey> _keys;
18+
private readonly UnmanagedArray<TValue> _values;
19+
private readonly UnmanagedArray<byte> _keyPresence;
20+
21+
private readonly int _capacity;
22+
23+
public int Count { get; }
24+
25+
public ImmutableLookupMapUnmanaged(IDictionary<TKey, TValue> data)
26+
{
27+
if (data == null)
28+
throw new ArgumentNullException(nameof(data));
29+
30+
Count = data.Count;
31+
_capacity = FindNextPrime(Count * 2);
32+
33+
_keys = new UnmanagedArray<TKey>(_capacity);
34+
_values = new UnmanagedArray<TValue>(_capacity);
35+
_keyPresence = new UnmanagedArray<byte>(_capacity);
36+
37+
foreach (var (key, value) in data)
38+
{
39+
for (var i = 0; i < _capacity; i++)
40+
{
41+
var hash = (GetHash(key, _capacity) + i * i) % _capacity;
42+
43+
if (_keyPresence[hash] == 0)
44+
{
45+
_keys[hash] = key;
46+
_values[hash] = value;
47+
_keyPresence[hash] = 1;
48+
break;
49+
}
50+
51+
if (_keys[hash].Equals(key))
52+
throw new InvalidOperationException($"Duplicate key detected: {key}");
53+
}
54+
}
55+
}
56+
57+
public TValue Get(TKey key)
58+
{
59+
var hash = GetHash(key, _capacity);
60+
var originalHash = hash;
61+
62+
while (_keyPresence[hash] != 0)
63+
{
64+
if (_keys[hash].Equals(key))
65+
return _values[hash];
66+
67+
hash = (hash + 1) % _capacity;
68+
if (hash == originalHash)
69+
break;
70+
}
71+
72+
throw new KeyNotFoundException($"Key '{key}' not found in lookup.");
73+
}
74+
75+
public bool TryGetValue(TKey key, out TValue value)
76+
{
77+
var hash = GetHash(key, _capacity);
78+
var originalHash = hash;
79+
80+
while (_keyPresence[hash] != 0)
81+
{
82+
if (_keys[hash].Equals(key))
83+
{
84+
value = _values[hash];
85+
return true;
86+
}
87+
88+
hash = (hash + 1) % _capacity;
89+
if (hash == originalHash)
90+
break;
91+
}
92+
93+
value = default;
94+
return false;
95+
}
96+
97+
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
98+
{
99+
for (var i = 0; i < _capacity; i++)
100+
{
101+
if (_keyPresence[i] != 0)
102+
yield return new KeyValuePair<TKey, TValue>(_keys[i], _values[i]);
103+
}
104+
}
105+
106+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
107+
108+
public void Dispose()
109+
{
110+
_keys.Dispose();
111+
_values.Dispose();
112+
_keyPresence.Dispose();
113+
}
114+
115+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
116+
private static int GetHash(TKey key, int capacity)
117+
{
118+
return Math.Abs(key.GetHashCode() % capacity);
119+
}
120+
121+
private static int FindNextPrime(int number)
122+
{
123+
while (!IsPrime(number))
124+
number++;
125+
return number;
126+
}
127+
128+
private static bool IsPrime(int number)
129+
{
130+
if (number < 2) return false;
131+
132+
foreach (var prime in SharedResources.SmallPrimes)
133+
{
134+
if (number == prime) return true;
135+
if (number % prime == 0) return false;
136+
}
137+
138+
for (var i = 201; i * i <= number; i += 2)
139+
if (number % i == 0)
140+
return false;
141+
142+
return true;
143+
}
144+
}
145+
}

ExtendedSystemObjects/UnmanagedArray.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ public void Resize(int newSize)
190190
}
191191
}
192192

193-
194193
/// <inheritdoc />
195194
/// <summary>
196195
/// Clears the array by setting all elements to zero.

0 commit comments

Comments
 (0)