Skip to content

Commit bf52061

Browse files
committed
optimized stack and queue
1 parent 2f27121 commit bf52061

File tree

4 files changed

+182
-178
lines changed

4 files changed

+182
-178
lines changed

Source/Base/Collections/Spring.Collections.Base.pas

Lines changed: 61 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -512,18 +512,19 @@ TCircularArrayBuffer<T> = class(TEnumerableBase<T>)
512512
private
513513
{$REGION 'Nested Types'}
514514
type
515-
TEnumerator = class(TRefCountedObject, IEnumerator<T>)
516-
private
515+
PEnumerator = ^TEnumerator;
516+
TEnumerator = record
517+
Vtable: Pointer;
518+
RefCount: Integer;
519+
TypeInfo: PTypeInfo;
517520
{$IFDEF AUTOREFCOUNT}[Unsafe]{$ENDIF}
518521
fSource: TCircularArrayBuffer<T>;
519-
fIndex: Integer;
522+
fIndex, fCount: Integer;
520523
fVersion: Integer;
521524
fCurrent: T;
522525
function GetCurrent: T;
523-
public
524-
constructor Create(const source: TCircularArrayBuffer<T>);
525-
destructor Destroy; override;
526526
function MoveNext: Boolean;
527+
class var Enumerator_Vtable: TEnumeratorVtable;
527528
end;
528529
ItemType = TTypeInfo<T>;
529530
PT = ^T;
@@ -536,7 +537,7 @@ TEnumerator = class(TRefCountedObject, IEnumerator<T>)
536537
fVersion: Integer;
537538
fHead: Integer;
538539
fTail: Integer;
539-
function GetTail: PT; inline;
540+
function GetTail: Integer; inline;
540541
protected
541542
{$REGION 'Property Accessors'}
542543
function GetCapacity: Integer; inline;
@@ -553,12 +554,11 @@ TEnumerator = class(TRefCountedObject, IEnumerator<T>)
553554
procedure DeleteFromHead(action: TCollectionChangedAction); inline;
554555
procedure DeleteFromTail(action: TCollectionChangedAction); inline;
555556

556-
procedure DoNotify(const item: T; action: TCollectionChangedAction); inline;
557557
property Capacity: Integer read GetCapacity;
558558
property Count: Integer read GetCount;
559559
property Items: TArray<T> read fItems;
560560
property Head: Integer read fHead;
561-
property Tail: PT read GetTail;
561+
property Tail: Integer read GetTail;
562562
property OwnsObjects: Boolean read GetOwnsObjects;
563563
public
564564
constructor Create(capacity: Integer = 0; ownsObjects: Boolean = False);
@@ -2108,13 +2108,6 @@ procedure TCircularArrayBuffer<T>.Clear;
21082108
DeleteFromHead(caRemoved);
21092109
end;
21102110

2111-
procedure TCircularArrayBuffer<T>.DoNotify(const item: T;
2112-
action: TCollectionChangedAction);
2113-
begin
2114-
if Assigned(fOnChanged) and fOnChanged.CanInvoke then
2115-
fOnChanged.Invoke(Self, item, action);
2116-
end;
2117-
21182111
function TCircularArrayBuffer<T>.GetCapacity: Integer;
21192112
begin
21202113
Result := fCapacity;
@@ -2127,7 +2120,14 @@ function TCircularArrayBuffer<T>.GetCount: Integer;
21272120

21282121
function TCircularArrayBuffer<T>.GetEnumerator: IEnumerator<T>;
21292122
begin
2130-
Result := TEnumerator.Create(Self);
2123+
_AddRef;
2124+
with PEnumerator(TEnumeratorBlock.Create(@Result, @TEnumerator.Enumerator_Vtable,
2125+
TypeInfo(TEnumerator), @TEnumerator.GetCurrent, @TEnumerator.MoveNext))^ do
2126+
begin
2127+
fSource := Self;
2128+
fCount := Self.Count;
2129+
fVersion := Self.fVersion;
2130+
end;
21312131
end;
21322132

21332133
function TCircularArrayBuffer<T>.GetIsEmpty: Boolean;
@@ -2145,15 +2145,14 @@ function TCircularArrayBuffer<T>.GetOwnsObjects: Boolean;
21452145
Result := {$IFDEF DELPHIXE7_UP}(GetTypeKind(T) = tkClass) and {$ENDIF}(fCount < 0);
21462146
end;
21472147

2148-
function TCircularArrayBuffer<T>.GetTail: PT;
2148+
function TCircularArrayBuffer<T>.GetTail: Integer;
21492149
var
21502150
index: Integer;
21512151
begin
21522152
index := fTail;
2153-
if index > 0 then
2154-
Result := @fItems[index - 1]
2155-
else
2156-
Result := @fItems[fCapacity - 1];
2153+
if index = 0 then
2154+
index := fCapacity;
2155+
Result := index - 1;
21572156
end;
21582157

21592158
procedure TCircularArrayBuffer<T>.AddToHead(const item: T);
@@ -2172,7 +2171,8 @@ procedure TCircularArrayBuffer<T>.AddToHead(const item: T);
21722171
fItems[index] := item;
21732172
fHead := index;
21742173

2175-
DoNotify(item, caAdded);
2174+
if Assigned(fOnChanged) and fOnChanged.CanInvoke then
2175+
fOnChanged.Invoke(Self, item, caAdded);
21762176
end;
21772177

21782178
procedure TCircularArrayBuffer<T>.AddToTail(const item: T);
@@ -2190,7 +2190,9 @@ procedure TCircularArrayBuffer<T>.AddToTail(const item: T);
21902190
if index = fCapacity then
21912191
index := 0;
21922192
fTail := index;
2193-
DoNotify(item, caAdded);
2193+
2194+
if Assigned(fOnChanged) and fOnChanged.CanInvoke then
2195+
fOnChanged.Invoke(Self, item, caAdded);
21942196
end;
21952197

21962198
procedure TCircularArrayBuffer<T>.DeleteFromHead(action: TCollectionChangedAction);
@@ -2210,7 +2212,8 @@ procedure TCircularArrayBuffer<T>.DeleteFromHead(action: TCollectionChangedActio
22102212
index := 0;
22112213
fHead := index;
22122214

2213-
DoNotify(item^, action);
2215+
if Assigned(fOnChanged) and fOnChanged.CanInvoke then
2216+
fOnChanged.Invoke(Self, item^, action);
22142217
if OwnsObjects and (action = caRemoved) then
22152218
FreeObject(item^);
22162219
item^ := Default(T);
@@ -2233,7 +2236,8 @@ procedure TCircularArrayBuffer<T>.DeleteFromTail(action: TCollectionChangedActio
22332236
item := @fItems[index];
22342237
fTail := index;
22352238

2236-
DoNotify(item^, action);
2239+
if Assigned(fOnChanged) and fOnChanged.CanInvoke then
2240+
fOnChanged.Invoke(Self, item^, action);
22372241
if OwnsObjects and (action = caRemoved) then
22382242
FreeObject(item^);
22392243
item^ := Default(T);
@@ -2282,20 +2286,24 @@ procedure TCircularArrayBuffer<T>.TrimExcess;
22822286

22832287
function TCircularArrayBuffer<T>.TryGetFirst(var value: T): Boolean;
22842288
begin
2285-
Result := Count > 0;
2286-
if Result then
2287-
value := fItems[fHead]
2288-
else
2289-
value := Default(T);
2289+
if Count > 0 then
2290+
begin
2291+
value := fItems[fHead];
2292+
Exit(True);
2293+
end;
2294+
value := Default(T);
2295+
Result := False;
22902296
end;
22912297

22922298
function TCircularArrayBuffer<T>.TryGetLast(var value: T): Boolean;
22932299
begin
2294-
Result := Count > 0;
2295-
if Result then
2296-
value := Tail^
2297-
else
2298-
value := Default(T);
2300+
if Count > 0 then
2301+
begin
2302+
value := fItems[Tail];
2303+
Exit(True);
2304+
end;
2305+
value := Default(T);
2306+
Result := False;
22992307
end;
23002308

23012309
procedure TCircularArrayBuffer<T>.SetCapacity(value: Integer);
@@ -2377,39 +2385,33 @@ procedure TCircularArrayBuffer<T>.SetOwnsObjects(value: Boolean);
23772385

23782386
{$REGION 'TCircularArrayBuffer<T>.TEnumerator'}
23792387

2380-
constructor TCircularArrayBuffer<T>.TEnumerator.Create(
2381-
const source: TCircularArrayBuffer<T>);
2382-
begin
2383-
fSource := source;
2384-
fSource._AddRef;
2385-
fVersion := fSource.fVersion;
2386-
end;
2387-
2388-
destructor TCircularArrayBuffer<T>.TEnumerator.Destroy;
2389-
begin
2390-
fSource._Release;
2391-
end;
2392-
23932388
function TCircularArrayBuffer<T>.TEnumerator.GetCurrent: T;
23942389
begin
23952390
Result := fCurrent;
23962391
end;
23972392

23982393
function TCircularArrayBuffer<T>.TEnumerator.MoveNext: Boolean;
2394+
var
2395+
source: TCircularArrayBuffer<T>;
2396+
index: Integer;
23992397
begin
2400-
if fVersion = fSource.fVersion then
2398+
source := fSource;
2399+
if fVersion = source.fVersion then
24012400
begin
2402-
Result := fIndex < fSource.Count;
2403-
if Result then
2401+
index := fIndex;
2402+
if index < fCount then
24042403
begin
2405-
fCurrent := fSource.fItems[(fSource.fHead + fIndex) mod fSource.fCapacity];
2404+
Inc(index, source.fHead);
2405+
if index >= source.fCapacity then
2406+
Dec(index, source.fCapacity);
2407+
fCurrent := source.fItems[index];
24062408
Inc(fIndex);
2407-
end
2408-
else
2409-
fCurrent := Default(T);
2410-
end
2411-
else
2412-
Result := RaiseHelper.EnumFailedVersion;
2409+
Exit(True);
2410+
end;
2411+
fCurrent := Default(T);
2412+
Exit(False);
2413+
end;
2414+
Result := RaiseHelper.EnumFailedVersion;
24132415
end;
24142416

24152417
{$ENDREGION}

Source/Base/Collections/Spring.Collections.Queues.pas

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -209,38 +209,40 @@ function TAbstractQueue<T>.PeekOrDefault: T;
209209

210210
function TAbstractQueue<T>.TryDequeue(var item: T): Boolean;
211211
begin
212-
Result := Count > 0;
213-
if Result then
212+
if Count > 0 then
214213
begin
215214
if OwnsObjects then
216215
item := Default(T)
217216
else
218217
item := Items[Head];
219218
DeleteFromHead(caRemoved);
220-
end
221-
else
222-
item := Default(T);
219+
Exit(True);
220+
end;
221+
item := Default(T);
222+
Result := False;
223223
end;
224224

225225
function TAbstractQueue<T>.TryExtract(var item: T): Boolean;
226226
begin
227-
Result := Count > 0;
228-
if Result then
227+
if Count > 0 then
229228
begin
230229
item := Items[Head];
231230
DeleteFromHead(caExtracted);
232-
end
233-
else
234-
item := Default(T);
231+
Exit(True);
232+
end;
233+
item := Default(T);
234+
Result := False;
235235
end;
236236

237237
function TAbstractQueue<T>.TryPeek(var item: T): Boolean;
238238
begin
239-
Result := Count > 0;
240-
if Result then
241-
item := Items[Head]
242-
else
243-
item := Default(T);
239+
if Count > 0 then
240+
begin
241+
item := Items[Head];
242+
Exit(True);
243+
end;
244+
item := Default(T);
245+
Result := False;
244246
end;
245247

246248
{$ENDREGION}
@@ -293,10 +295,9 @@ function TBoundedQueue<T>.Enqueue(const item: T): Boolean;
293295
if Count <> Capacity then
294296
begin
295297
AddToTail(item);
296-
Result := True;
297-
end
298-
else
299-
Result := False;
298+
Exit(True);
299+
end;
300+
Result := False;
300301
end;
301302

302303
{$ENDREGION}
@@ -338,7 +339,7 @@ function TAbstractDeque<T>.RemoveLast: T;
338339
if OwnsObjects then
339340
Result := Default(T)
340341
else
341-
Result := Tail^;
342+
Result := Items[Tail];
342343
DeleteFromTail(caRemoved);
343344
end
344345
else
@@ -360,7 +361,7 @@ function TAbstractDeque<T>.ExtractLast: T;
360361
begin
361362
if Count > 0 then
362363
begin
363-
Result := Tail^;
364+
Result := Items[Tail];
364365
DeleteFromTail(caExtracted);
365366
end
366367
else
@@ -369,56 +370,56 @@ function TAbstractDeque<T>.ExtractLast: T;
369370

370371
function TAbstractDeque<T>.TryRemoveFirst(var item: T): Boolean;
371372
begin
372-
Result := Count > 0;
373-
if Result then
373+
if Count > 0 then
374374
begin
375375
if OwnsObjects then
376376
item := Default(T)
377377
else
378378
item := Items[Head];
379379
DeleteFromHead(caRemoved);
380-
end
381-
else
382-
item := Default(T);
380+
Exit(True);
381+
end;
382+
item := Default(T);
383+
Result := False;
383384
end;
384385

385386
function TAbstractDeque<T>.TryRemoveLast(var item: T): Boolean;
386387
begin
387-
Result := Count > 0;
388-
if Result then
388+
if Count > 0 then
389389
begin
390390
if OwnsObjects then
391391
item := Default(T)
392392
else
393-
item := Tail^;
393+
item := Items[Tail];
394394
DeleteFromTail(caRemoved);
395-
end
396-
else
397-
item := Default(T);
395+
Exit(True);
396+
end;
397+
item := Default(T);
398+
Result := False;
398399
end;
399400

400401
function TAbstractDeque<T>.TryExtractFirst(var item: T): Boolean;
401402
begin
402-
Result := Count > 0;
403-
if Result then
403+
if Count > 0 then
404404
begin
405405
item := Items[Head];
406406
DeleteFromHead(caExtracted);
407-
end
408-
else
409-
item := Default(T);
407+
Exit(True);
408+
end;
409+
item := Default(T);
410+
Result := False;
410411
end;
411412

412413
function TAbstractDeque<T>.TryExtractLast(var item: T): Boolean;
413414
begin
414-
Result := Count > 0;
415-
if Result then
415+
if Count > 0 then
416416
begin
417-
item := Tail^;
417+
item := Items[Tail];
418418
DeleteFromTail(caExtracted);
419-
end
420-
else
421-
item := Default(T);
419+
Exit(True);
420+
end;
421+
item := Default(T);
422+
Result := False;
422423
end;
423424

424425
{$ENDREGION}

0 commit comments

Comments
 (0)