@@ -12,10 +12,10 @@ public unsafe struct UnsafeQueue<T> : IFreeable where T : unmanaged
1212 private const int DefaultCapacity = 4 ;
1313
1414 private T * items ;
15- private T * head ;
16- private T * tail ;
17- private int size ;
18- private int capacity ;
15+ private nint front ;
16+ private nint rear ;
17+ private nint size ;
18+ private nint capacity ;
1919
2020 /// <summary>
2121 /// Initializes a new instance of the <see cref="UnsafeQueue{T}"/> struct with the default capacity.
@@ -37,24 +37,48 @@ public UnsafeQueue(int capacity)
3737 /// <summary>
3838 /// Gets the number of elements in the queue.
3939 /// </summary>
40- public readonly int Size => size ;
40+ public readonly nint Size => size ;
4141
4242 /// <summary>
4343 /// Gets or sets the capacity of the queue.
4444 /// </summary>
45- public int Capacity
45+ public nint Capacity
4646 {
4747 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
4848 readonly get => capacity ;
4949 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
5050 set
5151 {
52+ if ( value == capacity )
53+ {
54+ return ;
55+ }
56+
57+ if ( items == null )
58+ {
59+ items = AllocT < T > ( value ) ;
60+ return ;
61+ }
62+
5263 var tmp = AllocT < T > ( value ) ;
53- var oldsize = size * sizeof ( T ) ;
54- var newsize = value * sizeof ( T ) ;
55- Buffer . MemoryCopy ( items , tmp , newsize , oldsize > newsize ? newsize : oldsize ) ;
64+
65+ if ( size > 0 )
66+ {
67+ if ( front <= rear )
68+ {
69+ MemcpyT ( items + front , tmp , value , size ) ;
70+ }
71+ else
72+ {
73+ MemcpyT ( items + front , tmp , value , capacity - front ) ;
74+ MemcpyT ( items , tmp + ( capacity - front ) , value , rear ) ;
75+ }
76+ }
77+
5678 Free ( items ) ;
57- head = tail = items = tmp ;
79+ items = tmp ;
80+ front = 0 ;
81+ rear = size - 1 ;
5882 capacity = value ;
5983 size = capacity < size ? capacity : size ;
6084 }
@@ -71,6 +95,21 @@ public T this[int index]
7195 set => items [ index ] = value ;
7296 }
7397
98+ /// <summary>
99+ /// Gets the pointer to the items of the queue.
100+ /// </summary>
101+ public readonly T * Items => items ;
102+
103+ /// <summary>
104+ /// Gets the pointer to the front element of the queue.
105+ /// </summary>
106+ public readonly T * Front => items + front ;
107+
108+ /// <summary>
109+ /// Gets the pointer to the rear element of the queue.
110+ /// </summary>
111+ public readonly T * Rear => items + rear ;
112+
74113 /// <summary>
75114 /// Initializes the queue with the default capacity.
76115 /// </summary>
@@ -91,9 +130,9 @@ public void Init(int capacity)
91130 }
92131
93132 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
94- private void Grow ( int capacity )
133+ private void Grow ( nint capacity )
95134 {
96- int newcapacity = size == 0 ? DefaultCapacity : 2 * size ;
135+ nint newcapacity = size == 0 ? DefaultCapacity : 2 * size ;
97136
98137 if ( newcapacity < capacity )
99138 {
@@ -103,12 +142,21 @@ private void Grow(int capacity)
103142 Capacity = newcapacity ;
104143 }
105144
145+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
146+ private void Shrink ( )
147+ {
148+ if ( capacity > DefaultCapacity && capacity > size * 2 )
149+ {
150+ Capacity = size ;
151+ }
152+ }
153+
106154 /// <summary>
107155 /// Ensures that the queue has the specified capacity.
108156 /// </summary>
109157 /// <param name="capacity">The desired capacity.</param>
110158 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
111- public void EnsureCapacity ( int capacity )
159+ public void EnsureCapacity ( nint capacity )
112160 {
113161 if ( this . capacity < capacity )
114162 {
@@ -124,8 +172,8 @@ public void EnsureCapacity(int capacity)
124172 public void Enqueue ( T item )
125173 {
126174 EnsureCapacity ( size + 1 ) ;
127- head ++ ;
128- * head = item ;
175+ rear = ( rear + 1 ) % capacity ;
176+ items [ rear ] = item ;
129177 size ++ ;
130178 }
131179
@@ -136,15 +184,17 @@ public void Enqueue(T item)
136184 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
137185 public T Dequeue ( )
138186 {
139- var tmp = * tail ;
140- * tail = default ;
141- tail ++ ;
142- if ( head == tail )
187+ if ( size == 0 )
143188 {
144- head = tail = items ;
189+ throw new InvalidOperationException ( "Queue is empty." ) ;
145190 }
191+
192+ T item = items [ front ] ;
193+ front = ( front + 1 ) % capacity ;
146194 size -- ;
147- return tmp ;
195+ Shrink ( ) ;
196+
197+ return item ;
148198 }
149199
150200 /// <summary>
@@ -160,14 +210,12 @@ public bool TryDequeue(out T item)
160210 item = default ;
161211 return false ;
162212 }
163- item = * tail ;
164- * tail = default ;
165- tail ++ ;
166- if ( head == tail )
167- {
168- head = tail = items ;
169- }
213+
214+ item = items [ front ] ;
215+ front = ( front + 1 ) % capacity ;
170216 size -- ;
217+ Shrink ( ) ;
218+
171219 return true ;
172220 }
173221
@@ -178,9 +226,9 @@ public bool TryDequeue(out T item)
178226 /// <param name="arrayIndex">The starting index in the destination array.</param>
179227 /// <param name="arraySize">The size of the destination array.</param>
180228 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
181- public readonly void CopyTo ( T * array , uint arrayIndex , uint arraySize )
229+ public readonly void CopyTo ( T * array , int arrayIndex , int arraySize )
182230 {
183- Buffer . MemoryCopy ( items , & array [ arrayIndex ] , ( arraySize - arrayIndex ) * sizeof ( T ) , size * sizeof ( T ) ) ;
231+ MemcpyT ( items , & array [ arrayIndex ] , arraySize - arrayIndex , size ) ;
184232 }
185233
186234 /// <summary>
@@ -192,9 +240,9 @@ public readonly void CopyTo(T* array, uint arrayIndex, uint arraySize)
192240 /// <param name="offset">The starting index in the queue.</param>
193241 /// <param name="count">The number of elements to copy.</param>
194242 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
195- public void CopyTo ( T * array , uint arrayIndex , uint arraySize , uint offset , uint count )
243+ public void CopyTo ( T * array , int arrayIndex , int arraySize , int offset , int count )
196244 {
197- Buffer . MemoryCopy ( & items [ offset ] , & array [ arrayIndex ] , ( arraySize - arrayIndex ) * sizeof ( T ) , ( count - offset ) * sizeof ( T ) ) ;
245+ MemcpyT ( & items [ offset ] , & array [ arrayIndex ] , arraySize - arrayIndex , count - offset ) ;
198246 }
199247
200248 /// <summary>
@@ -203,13 +251,10 @@ public void CopyTo(T* array, uint arrayIndex, uint arraySize, uint offset, uint
203251 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
204252 public void Clear ( )
205253 {
206- var ptr = items ;
207- for ( int i = 0 ; i < size ; i ++ )
208- {
209- ptr [ i ] = default ;
210- }
254+ ZeroMemoryT ( items , capacity ) ;
211255 size = 0 ;
212- head = tail = items ;
256+ front = 0 ;
257+ rear = 0 ;
213258 }
214259
215260 /// <summary>
@@ -218,17 +263,13 @@ public void Clear()
218263 /// <param name="item">The item to search for.</param>
219264 /// <returns><c>true</c> if the item is found; otherwise, <c>false</c>.</returns>
220265 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
221- public bool Contains ( T * item )
266+ public bool Contains ( T item )
222267 {
223- for ( int i = 0 ; i < size ; i ++ )
268+ for ( nint i = 0 ; i < size ; i ++ )
224269 {
225- var current = & items [ i ] ;
226- if ( current == null )
227- {
228- break ;
229- }
270+ var current = items [ ( front + i ) % capacity ] ;
230271
231- if ( current == item )
272+ if ( current . Equals ( item ) )
232273 {
233274 return true ;
234275 }
@@ -243,12 +284,11 @@ public bool Contains(T* item)
243284 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
244285 public void Release ( )
245286 {
246- Free ( items ) ;
247- items = null ;
248- head = null ;
249- tail = null ;
250- capacity = 0 ;
251- size = 0 ;
287+ if ( items != null )
288+ {
289+ Free ( items ) ;
290+ this = default ;
291+ }
252292 }
253293 }
254294}
0 commit comments