11/*
22 * COPYRIGHT: See COPYING in the top level directory
3- * PROJECT: ExtendedSystemObjects
4- * FILE: ImmutableLookupMap.cs
5- * PURPOSE: A high-performance, immutable lookup map that uses an array-based internal structure for fast key-value lookups.
6- * This version is limited to unmanaged types and uses UnmanagedArray<T>.
3+ * PROJECT: ExtendedSystemObjects
4+ * FILE: ImmutableLookupMap.cs
5+ * PURPOSE: A high-performance, immutable lookup map that uses an array-based internal structure for fast key-value lookups.
6+ * This version is limited to unmanaged types and uses UnmanagedArray<T>.
77 * PROGRAMMER: Peter Geinitz (Wayfarer)
88 */
99
@@ -30,8 +30,8 @@ public sealed unsafe class ImmutableLookupMapUnmanaged<TKey, TValue> : IDisposab
3030 /// <summary>
3131 /// Internal entry structure to ensure data locality (Cache-friendly).
3232 /// </summary>
33- [ StructLayout ( LayoutKind . Sequential , Pack = 1 ) ]
34- private struct Entry
33+ [ StructLayout ( LayoutKind . Sequential ) ]
34+ internal struct Entry
3535 {
3636 public byte IsPresent ;
3737 public TKey Key ;
@@ -53,6 +53,11 @@ private struct Entry
5353 /// </summary>
5454 private readonly UnmanagedArray < Entry > _entries ;
5555
56+ /// <summary>
57+ /// The disposed
58+ /// </summary>
59+ private bool _disposed ;
60+
5661 /// <summary>
5762 /// Initializes a new instance of the <see cref="ImmutableLookupMapUnmanaged{TKey, TValue}" /> class
5863 /// with the specified key-value data.
@@ -117,44 +122,12 @@ public ImmutableLookupMapUnmanaged(IDictionary<TKey, TValue> data)
117122 /// </summary>
118123 public void Dispose ( )
119124 {
125+ if ( _disposed ) return ;
120126 _entries . Dispose ( ) ;
127+ _disposed = true ;
121128 }
122129
123130 /// <inheritdoc />
124- /// <summary>
125- /// Returns an enumerator for iterating over the key-value pairs in the map.
126- /// </summary>
127- /// <remarks>
128- /// Note: We avoid pointers here because yield return cannot exist in an unsafe context
129- /// that captures pointers. We use the array indexer instead.
130- /// </remarks>
131- public IEnumerator < KeyValuePair < TKey , TValue > > GetEnumerator ( )
132- {
133- for ( var i = 0 ; i < _capacity ; i ++ )
134- {
135- // We use the safe indexer of UnmanagedArray.
136- // This causes a value-copy of the Entry struct, but it's yield-compatible.
137- var entry = _entries [ i ] ;
138-
139- if ( entry . IsPresent != 0 )
140- {
141- yield return new KeyValuePair < TKey , TValue > ( entry . Key , entry . Value ) ;
142- }
143- }
144- }
145-
146- /// <inheritdoc />
147- /// <summary>
148- /// Returns an enumerator that iterates through a collection.
149- /// </summary>
150- /// <returns>
151- /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
152- /// </returns>
153- IEnumerator IEnumerable . GetEnumerator ( )
154- {
155- return GetEnumerator ( ) ;
156- }
157-
158131 /// <summary>
159132 /// Gets the value associated with the specified key.
160133 /// </summary>
@@ -224,5 +197,91 @@ private static int GetHash(TKey key)
224197 {
225198 return key . GetHashCode ( ) ;
226199 }
200+
201+ /// <summary>
202+ /// Gets the enumerator.
203+ /// </summary>
204+ /// <returns>An enumerator for the lookup map.</returns>
205+ public Enumerator GetEnumerator ( )
206+ {
207+ return new Enumerator ( _entries . Pointer , _capacity ) ;
208+ }
209+
210+ /// <inheritdoc />
211+ IEnumerator IEnumerable . GetEnumerator ( )
212+ {
213+ return GetEnumerator ( ) ;
214+ }
215+
216+ /// <inheritdoc />
217+ IEnumerator < KeyValuePair < TKey , TValue > > IEnumerable < KeyValuePair < TKey , TValue > > . GetEnumerator ( )
218+ {
219+ return GetEnumerator ( ) ;
220+ }
221+
222+ /// <summary>
223+ /// High performance enumerator for iterating over the entries in the lookup map. Uses unsafe code and pointer arithmetic for maximum speed.
224+ /// </summary>
225+ /// <seealso cref="System.IDisposable" />
226+ /// <seealso cref="System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey, TValue>>" />
227+ public unsafe struct Enumerator : IEnumerator < KeyValuePair < TKey , TValue > >
228+ {
229+ private readonly Entry * _entries ;
230+ private readonly int _capacity ;
231+ private int _index ;
232+ private KeyValuePair < TKey , TValue > _current ;
233+
234+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
235+ internal Enumerator ( Entry * entries , int capacity )
236+ {
237+ _entries = entries ;
238+ _capacity = capacity ;
239+ _index = - 1 ;
240+ _current = default ;
241+ }
242+
243+ /// <inheritdoc />
244+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
245+ public bool MoveNext ( )
246+ {
247+ // Nutzt superschnelle Pointer-Arithmetik statt des Array-Indexers
248+ while ( ++ _index < _capacity )
249+ {
250+ Entry * entry = _entries + _index ;
251+ if ( entry ->IsPresent != 0 )
252+ {
253+ _current = new KeyValuePair < TKey , TValue > ( entry ->Key , entry ->Value ) ;
254+ return true ;
255+ }
256+ }
257+ return false ;
258+ }
259+
260+ /// <inheritdoc />
261+ public readonly KeyValuePair < TKey , TValue > Current
262+ {
263+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
264+ get => _current ;
265+ }
266+
267+ /// <inheritdoc />
268+ readonly object IEnumerator . Current => Current ;
269+
270+ /// <summary>
271+ /// Sets the enumerator to its initial position, which is before the first element in the collection.
272+ /// </summary>
273+ public void Reset ( )
274+ {
275+ _index = - 1 ;
276+ _current = default ;
277+ }
278+
279+ /// <summary>
280+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
281+ /// </summary>
282+ public readonly void Dispose ( )
283+ {
284+ }
285+ }
227286 }
228287}
0 commit comments