Skip to content

Commit 9796e06

Browse files
committed
Refactor memory handling and add intrusive lists
Updated `MurmurHash3.cs` and `StringSpan.cs` to use `nuint` for length-related variables, improving support for large memory spans. Added `Memcmp` and `MemcmpT` methods in `Utils.cs` for efficient memory comparison. Introduced `UnsafeSpan<T>` for unmanaged memory spans with slicing, indexing, and equality checks. Added `IIntrusiveDoubleLinkedListNode<T>` and `IIntrusiveSingleLinkedListNode<T>` interfaces, along with `IntrusiveDoubleLinkedList<T>` and `IntrusiveSingleLinkedList<T>` structs for managing linked lists of unmanaged nodes. Incremented package version to `2.2.6` and made general improvements to type safety, performance, and code maintainability.
1 parent 91287ec commit 9796e06

File tree

9 files changed

+689
-36
lines changed

9 files changed

+689
-36
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace HexaModManager.Core.FileDB
2+
{
3+
public unsafe interface IIntrusiveDoubleLinkedListNode<T> where T : unmanaged, IIntrusiveDoubleLinkedListNode<T>
4+
{
5+
public T* Next { get; set; }
6+
7+
public T* Prev { get; set; }
8+
}
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace HexaModManager.Core.FileDB
2+
{
3+
public unsafe interface IIntrusiveSingleLinkedListNode<T> where T : unmanaged, IIntrusiveSingleLinkedListNode<T>
4+
{
5+
public T* Next { get; set; }
6+
}
7+
}
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
namespace HexaModManager.Core.FileDB
2+
{
3+
using Hexa.NET.Utilities;
4+
using System.Collections;
5+
6+
public unsafe struct IntrusiveDoubleLinkedList<T> : IEnumerable<Pointer<T>> where T : unmanaged, IIntrusiveDoubleLinkedListNode<T>
7+
{
8+
private T* head;
9+
private T* tail;
10+
private nuint count;
11+
12+
public readonly T* Head => head;
13+
14+
public readonly T* Tail => tail;
15+
16+
public readonly nuint Count => count;
17+
18+
public T* this[nuint index]
19+
{
20+
readonly get
21+
{
22+
var current = head;
23+
nuint i = 0;
24+
while (current != null)
25+
{
26+
if (i == index)
27+
{
28+
return current;
29+
}
30+
current = current->Next;
31+
++i;
32+
}
33+
throw new IndexOutOfRangeException();
34+
}
35+
set
36+
{
37+
var current = head;
38+
nuint i = 0;
39+
while (current != null)
40+
{
41+
if (i == index)
42+
{
43+
value->Prev = current->Prev;
44+
value->Next = current->Next;
45+
if (current->Prev != null)
46+
{
47+
current->Prev->Next = value;
48+
}
49+
else
50+
{
51+
head = value;
52+
}
53+
if (current->Next != null)
54+
{
55+
current->Next->Prev = value;
56+
}
57+
else
58+
{
59+
tail = value;
60+
}
61+
return;
62+
}
63+
current = current->Next;
64+
++i;
65+
}
66+
throw new IndexOutOfRangeException();
67+
}
68+
}
69+
70+
public void Append(T* node)
71+
{
72+
node->Next = null;
73+
node->Prev = tail;
74+
if (head == null)
75+
{
76+
head = node;
77+
tail = node;
78+
}
79+
else
80+
{
81+
tail->Next = node;
82+
tail = node;
83+
}
84+
++count;
85+
}
86+
87+
public void Prepend(T* node)
88+
{
89+
node->Prev = null;
90+
node->Next = head;
91+
if (head == null)
92+
{
93+
head = node;
94+
tail = node;
95+
}
96+
else
97+
{
98+
head->Prev = node;
99+
head = node;
100+
}
101+
++count;
102+
}
103+
104+
public T* PopFront()
105+
{
106+
if (head == null)
107+
{
108+
return null;
109+
}
110+
var node = head;
111+
head = head->Next;
112+
if (head != null)
113+
{
114+
head->Prev = null;
115+
}
116+
else
117+
{
118+
tail = null;
119+
}
120+
--count;
121+
return node;
122+
}
123+
124+
public T* PopBack()
125+
{
126+
if (tail == null)
127+
{
128+
return null;
129+
}
130+
var node = tail;
131+
tail = tail->Prev;
132+
if (tail != null)
133+
{
134+
tail->Next = null;
135+
}
136+
else
137+
{
138+
head = null;
139+
}
140+
--count;
141+
return node;
142+
}
143+
144+
public void Remove(T* node)
145+
{
146+
if (node->Prev != null)
147+
{
148+
node->Prev->Next = node->Next;
149+
}
150+
else
151+
{
152+
head = node->Next;
153+
}
154+
if (node->Next != null)
155+
{
156+
node->Next->Prev = node->Prev;
157+
}
158+
else
159+
{
160+
tail = node->Prev;
161+
}
162+
--count;
163+
}
164+
165+
public void Clear()
166+
{
167+
head = null;
168+
tail = null;
169+
count = 0;
170+
}
171+
172+
public struct Enumerator : IEnumerator<Pointer<T>>
173+
{
174+
private readonly T* head;
175+
private T* current;
176+
177+
public Enumerator(T* head)
178+
{
179+
this.head = head;
180+
current = null;
181+
}
182+
183+
public readonly Pointer<T> Current => current;
184+
185+
readonly object IEnumerator.Current => Current;
186+
187+
public bool MoveNext()
188+
{
189+
if (current == null)
190+
{
191+
current = head;
192+
}
193+
else
194+
{
195+
current = current->Next;
196+
}
197+
return current != null;
198+
}
199+
200+
public bool MovePrevious()
201+
{
202+
if (current == null)
203+
{
204+
return false;
205+
}
206+
else
207+
{
208+
current = current->Prev;
209+
}
210+
return current != null;
211+
}
212+
213+
public void Reset()
214+
{
215+
current = null;
216+
}
217+
218+
public readonly void Dispose()
219+
{
220+
}
221+
}
222+
223+
public readonly Enumerator GetEnumerator() => new(head);
224+
225+
readonly IEnumerator<Pointer<T>> IEnumerable<Pointer<T>>.GetEnumerator() => GetEnumerator();
226+
227+
readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
228+
}
229+
}

0 commit comments

Comments
 (0)