자유롭게 질의 및 응답을 할 수 있는 게시판입니다. 개발자 여러분의 답변이 큰 도움이 됩니다.
- 제품설치/등록 오류 문의: 설치/등록 Q&A 이용 (제품 구매 고객 한정)
Firemonkey 델파이 XE7에서 안드로이드로 실행시.apk raised exception class segmentation fault (11). 오류 (미해결중입니다)
2017.09.28 10:20
안녕하세요
델파이 XE7 System.Generics.Collections 사용시 32-bit 윈도우에서는 정상적으로 사용 가능합니다.
그런데 안드로이드 모바일에서 사용하면 오류가 납니다.
혹 안드로이드용, 윈도우용 System.Generics.Collections 화일이 따로 있는건가요?
오류메새지 : .apk raised exception class segmentation fault (11).
현재 제가 사용하고 있는 System.Generics.Collections 일부입니다
{*******************************************************}
{ }
{ CodeGear Delphi Runtime Library }
{ }
{ Copyright(c) 1995-2014 Embarcadero Technologies, Inc. }
{ }
{*******************************************************}
unit System.Generics.Collections;
{$R-,T-,X+,H+,B-}
interface
uses
System.Types, System.SysUtils, System.Generics.Defaults;
.
.
.
{ TList<T> }
function TList<T>.GetCapacity: Integer;
begin
Result := Length(FItems); <===== 이부분에 .apk raised exception class segmentation fault (11). 오류발생
end;
댓글 6
-
험프리
2017.09.28 14:56
-
delphi
2017.09.28 23:50
도움주셔서 감사합니다.
제가 사용 한 소스와 TimeCalculator 호출 소스, System.Generics.Collections; 입니다
중간마다 1),2),3) 으로 제가 디버깅 한 순서를 표시 해두었습니다
검토 부탁드립니다
=============== 작성한 소스 ===============
procedure TAttendanceInputView.CalcTime_Ver2;
var
StartTime: TDateTime;
EndTime: TDateTime;
ExtraStartTime: Extended;
ExtraEndTime: Extended;
begin
FDefaultTime := 0;
FOverTime := 0;
FNightTime := 0;
FHolidayTime := 0;
FHolidayOverTime := 0;
if (TimeOf(dtpStartTime.Time) = EncodeTime(0, 0, 0, 0))
and (TimeOf(dtpEndTime.Time) = EncodeTime(0, 0, 0, 0)) then
begin
Exit;
end;
if TimeOf(dtpStartTime.Time) < TimeOf(dtpEndTime.Time) then
begin
StartTime := DateOf(DateTimePicker.Date) + TimeOf(dtpStartTime.Time);
EndTime := DateOf(DateTimePicker.Date) + TimeOf(dtpEndTime.Time);
end
else
begin
StartTime := DateOf(DateTimePicker.Date) + TimeOf(dtpStartTime.Time);
EndTime := IncDay(DateOf(DateTimePicker.Date)) + TimeOf(dtpEndTime.Time);
end;
ExtraStartTime := 0;
ExtraEndTime := 0;
if not VarIsNull(cmbAttendanceCategory.EditValue) then
begin
if LookupModule.qry_ATTENDANCE_EXTRA_CATEGORY_IS_WORK.Value = 'N' then
begin
if TimeOf(dtpExtraStartTime.Time) < TimeOf(dtpExtraEndTime.Time) then
begin
ExtraStartTime := DateOf(DateTimePicker.Date) + TimeOf(dtpExtraStartTime.Time);
ExtraEndTime := DateOf(DateTimePicker.Date) + TimeOf(dtpExtraEndTime.Time);
end
else
begin
ExtraStartTime := DateOf(DateTimePicker.Date) + TimeOf(dtpExtraStartTime.Time);
ExtraEndTime := IncDay(DateOf(DateTimePicker.Date)) + TimeOf(dtpExtraEndTime.Time);
end;
end;
end;
FTimeCalculator.Init(StartTime, EndTime); <=== 1) 이문장 부터 호출 시작 입니다
DateOf(DateTimePicker.Date) + EncodeTime(12, 30, 0, 0),
DateOf(DateTimePicker.Date) + EncodeTime(13, 30, 0, 0)
);
FTimeCalculator.Exclude(
DateOf(DateTimePicker.Date) + EncodeTime(17, 30, 0, 0),
DateOf(DateTimePicker.Date) + EncodeTime(18, 30, 0, 0)
);
if (ExtraStartTime > 0) and (ExtraEndTime > 0) then
FTimeCalculator.Exclude(ExtraStartTime, ExtraEndTime);
FNightTime := FTimeCalculator.ToMinutesAndFree(FTimeCalculator.Intersects(
DateOf(DateTimePicker.Date) + EncodeTime(22, 0, 0, 0),
IncDay(DateOf(DateTimePicker.Date)) + EncodeTime(6, 0, 0, 0)
));
FTimeCalculator.Exclude(
DateOf(IncDay(DateTimePicker.Date)) + EncodeTime(0, 30, 0, 0),
DateOf(IncDay(DateTimePicker.Date)) + EncodeTime(1, 30, 0, 0)
);
FTimeCalculator.Exclude(
DateOf(IncDay(DateTimePicker.Date)) + EncodeTime(6, 30, 0, 0),
DateOf(IncDay(DateTimePicker.Date)) + EncodeTime(7, 30, 0, 0)
);
FDefaultTime := FTimeCalculator.ToMinutes(FTimeCalculator.TimeRanges);
if FDefaultTime > 8 * 60 then
begin
FOverTime := FDefaultTime - (8 * 60);
FDefaultTime := 8 * 60;
end;
if DayOfTheWeek(DateTimePicker.Date) in [DaySaturday, DaySunday] then
begin
FHolidayTime := FDefaultTime;
FHolidayOverTime := FOverTime;
FDefaultTime := 0;
FOverTime := 0;
end;
edDefaultTime.Text := Format('%.2d:%.2d', [FDefaultTime div 60, FDefaultTime mod 60]);
edOverTime.Text := Format('%.2d:%.2d', [FOverTime div 60, FOverTime mod 60]);
edHolidayTime.Text := Format('%.2d:%.2d', [FHolidayTime div 60, FHolidayTime mod 60]);
edHolidayOverTime.Text := Format('%.2d:%.2d', [FHolidayOverTime div 60, FHolidayOverTime mod 60]);
edNightTime.Text := Format('%.2d:%.2d', [FNightTime div 60, FNightTime mod 60]);
end;
-
delphi
2017.09.29 08:37
================== 호출한 소스 TimeCalculator 호출 (FTimeCalculator) ===========================
unit TimeCalculator;
interface
uses
System.DateUtils,
System.Generics.Collections;
type
TTimeRange = class
public
From: TDateTime;
&To: TDateTime;
constructor Create(AFrom: TDateTime; ATo: TDateTime);
function IsEmpty: Boolean;
end;
TTimeCalculator = class
private
FTimeRanges: TList<TTimeRange>;
function GetCount: Integer;
function GetRange(Index: Integer): TTimeRange;
public
constructor Create;
destructor Destroy; override;
procedure Init(AFrom: TDateTime; ATo: TDateTime); overload;
procedure Init(ATimeRange: TTimeRange); overload;
procedure Exclude(AFrom: TDateTime; ATo: TDateTime); overload;
procedure Exclude(ATimeRange: TTimeRange); overload;
function Intersects(AFrom: TDateTime; ATo: TDateTime): TList<TTimeRange>; overload;
function Intersects(ATimeRange: TTimeRange): TList<TTimeRange>; overload;
property Ranges[Index: Integer]: TTimeRange read GetRange;
property RangeCount: Integer read GetCount;
property TimeRanges: TList<TTimeRange> read FTimeRanges;
class function ToMinutes(TimeRanges: TList<TTimeRange>): Integer;
class function ToHours(TimeRanges: TList<TTimeRange>): Integer;
class function ToMinutesAndFree(TimeRanges: TList<TTimeRange>): Integer;
class function ToHoursAndFree(TimeRanges: TList<TTimeRange>): Integer;
class function Intersect(Left: TTimeRange; Right: TTimeRange): TTimeRange;
end;
implementation
{ TTimeCalculator }
constructor TTimeCalculator.Create;
begin
FTimeRanges := TObjectList<TTimeRange>.Create;
end;
destructor TTimeCalculator.Destroy;
begin
FTimeRanges.Free;
inherited;
end;
procedure TTimeCalculator.Exclude(ATimeRange: TTimeRange);
var
I: Integer;
TimeRange: TTimeRange;
begin
for I := FTimeRanges.Count - 1 downto 0 do
begin
TimeRange := Intersect(FTimeRanges.Items[I], ATimeRange);
try
if not TimeRange.IsEmpty then
begin
if (FTimeRanges.Items[I].&From < TimeRange.From)
and (TimeRange.&To < FTimeRanges.Items[I].&To) then
begin
FTimeRanges.Add(TTimeRange.Create(TimeRange.&To, FTimeRanges.Items[I].&To));
FTimeRanges.Items[I].&To := TimeRange.From;
end
else if (FTimeRanges.Items[I].&From < TimeRange.From)
and (TimeRange.&To = FTimeRanges.Items[I].&To) then
begin
FTimeRanges.Items[I].&To := TimeRange.From;
end
else if (FTimeRanges.Items[I].&From = TimeRange.From)
and (TimeRange.&To < FTimeRanges.Items[I].&To) then
begin
FTimeRanges.Items[I].From := TimeRange.&To;
end
else
begin
FTimeRanges.Delete(I);
end;
end;
finally
TimeRange.Free;
end;
end;
end;
procedure TTimeCalculator.Exclude(AFrom, ATo: TDateTime);
begin
Exclude(TTimeRange.Create(AFrom, ATo));
end;
function TTimeCalculator.GetCount: Integer;
begin
Result := FTimeRanges.Count;
end;
function TTimeCalculator.GetRange(Index: Integer): TTimeRange;
begin
Result := FTimeRanges.Items[Index];
end;
procedure TTimeCalculator.Init(AFrom, ATo: TDateTime);
begin
Init(TTimeRange.Create(AFrom, ATo)); //2) 여기서 호출시 오류 나는거 같습니다
end;
procedure TTimeCalculator.Init(ATimeRange: TTimeRange);
begin
FTimeRanges.Clear;
FTimeRanges.Add(ATimeRange);
end;
function TTimeCalculator.Intersects(AFrom, ATo: TDateTime): TList<TTimeRange>;
begin
Result := Intersects(TTimeRange.Create(AFrom, ATo));
end;
class function TTimeCalculator.Intersect(Left, Right: TTimeRange): TTimeRange;
begin
if (Left.&To > Right.From) and (Left.From < Right.&To) then
begin
Result := TTimeRange.Create(0, 0);
if Left.From < Right.From then
Result.From := Right.From
else
Result.From := Left.From;
if Left.&To < Right.&To then
Result.&To := Left.&To
else
Result.&To := Right.&To;
end
else
begin
Result := TTimeRange.Create(0, 0);
end;
end;
function TTimeCalculator.Intersects(ATimeRange: TTimeRange): TList<TTimeRange>;
var
I: Integer;
TimeRange: TTimeRange;
begin
Result := TObjectList<TTimeRange>.Create;
for I := 0 to FTimeRanges.Count - 1 do
begin
TimeRange := Intersect(FTimeRanges.Items[I], ATimeRange);
if TimeRange.IsEmpty then
TimeRange.Free
else
Result.Add(TimeRange);
end;
end;
class function TTimeCalculator.ToHours(TimeRanges: TList<TTimeRange>): Integer;
begin
Result := ToMinutes(TimeRanges) div 60;
end;
class function TTimeCalculator.ToHoursAndFree(
TimeRanges: TList<TTimeRange>): Integer;
begin
try
Result := ToHours(TimeRanges);
finally
TimeRanges.Free;
end;
end;
class function TTimeCalculator.ToMinutes(
TimeRanges: TList<TTimeRange>): Integer;
var
I: Integer;
begin
Result := 0;
for I := 0 to TimeRanges.Count - 1 do
Result := Result + MinutesBetween(TimeRanges.Items[I].From, TimeRanges.Items[I].&To);
end;
class function TTimeCalculator.ToMinutesAndFree(
TimeRanges: TList<TTimeRange>): Integer;
begin
try
Result := ToMinutes(TimeRanges);
finally
TimeRanges.Free;
end;
end;
{ TTimeRange }
constructor TTimeRange.Create(AFrom, ATo: TDateTime);
begin
From := AFrom;
&To := ATo;
end;
function TTimeRange.IsEmpty: Boolean;
begin
Result := From = &To;
end;
end.
======================================================================
-
delphi
2017.09.29 08:37
========================== System.Generics.Collections;===============================
{*******************************************************}
{ }
{ CodeGear Delphi Runtime Library }
{ }
{ Copyright(c) 1995-2014 Embarcadero Technologies, Inc. }
{ }
{*******************************************************}
unit System.Generics.Collections;
{$R-,T-,X+,H+,B-}
interface
uses
System.Types, System.SysUtils, System.Generics.Defaults;
type
TArray = class
private
class procedure QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>;
L, R: Integer); static;
class procedure CheckArrays(Source, Destination: Pointer; SourceIndex, SourceLength, DestIndex, DestLength, Count: NativeInt); static;
public
class procedure Sort<T>(var Values: array of T); overload; static;
class procedure Sort<T>(var Values: array of T; const Comparer: IComparer<T>); overload; static;
class procedure Sort<T>(var Values: array of T;
const Comparer: IComparer<T>; Index, Count: Integer); overload; static;
class function BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>;
Index, Count: Integer): Boolean; overload; static;
class function BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>): Boolean; overload; static;
class function BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer): Boolean; overload; static; static;
class procedure Copy<T>(const Source, Destination: array of T; SourceIndex, DestIndex, Count: NativeInt); overload; static;
class procedure Copy<T>(const Source, Destination: array of T; Count: NativeInt); overload; static;
end;
TCollectionNotification = (cnAdded, cnRemoved, cnExtracted);
TCollectionNotifyEvent<T> = procedure(Sender: TObject; const Item: T;
Action: TCollectionNotification) of object;
TEnumerator<T> = class abstract
protected
function DoGetCurrent: T; virtual; abstract;
function DoMoveNext: Boolean; virtual; abstract;
public
property Current: T read DoGetCurrent;
function MoveNext: Boolean;
end;
TEnumerable<T> = class abstract
private
{$HINTS OFF}
function ToArrayImpl(Count: Integer): TArray<T>; // used by descendants
{$HINTS ON}
protected
function DoGetEnumerator: TEnumerator<T>; virtual; abstract;
public
destructor Destroy; override;
function GetEnumerator: TEnumerator<T>;
function ToArray: TArray<T>; virtual;
end;
TArrayManager<T> = class abstract
public
procedure Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer); overload; virtual; abstract;
procedure Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer); overload; virtual; abstract;
procedure Finalize(var AArray: array of T; Index, Count: Integer); virtual; abstract;
end;
TMoveArrayManager<T> = class(TArrayManager<T>)
public
procedure Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer); overload; override;
procedure Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer); overload; override;
procedure Finalize(var AArray: array of T; Index, Count: Integer); override;
end;
{$IF Defined(WEAKREF)}
TManualArrayManager<T> = class(TArrayManager<T>)
public
procedure Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer); overload; override;
procedure Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer); overload; override;
procedure Finalize(var AArray: array of T; Index, Count: Integer); override;
end;
{$ENDIF}
TList<T> = class(TEnumerable<T>)
private
type
arrayofT = array of T;
var
FItems: arrayofT;
FCount: Integer;
FComparer: IComparer<T>;
FOnNotify: TCollectionNotifyEvent<T>;
FArrayManager: TArrayManager<T>;
function GetCapacity: Integer;
procedure SetCapacity(Value: Integer);
procedure SetCount(Value: Integer);
function GetItem(Index: Integer): T;
procedure SetItem(Index: Integer; const Value: T);
procedure Grow(ACount: Integer);
procedure GrowCheck(ACount: Integer); inline;
procedure DoDelete(Index: Integer; Notification: TCollectionNotification);
protected
function ItemValue(const Item: T): NativeInt;
function DoGetEnumerator: TEnumerator<T>; override;
procedure Notify(const Item: T; Action: TCollectionNotification); virtual;
public
type
TDirection = System.Types.TDirection;
TEmptyFunc = reference to function (const L, R: T): Boolean;
TListCompareFunc = reference to function (const L, R: T): Integer;
constructor Create; overload;
constructor Create(const AComparer: IComparer<T>); overload;
constructor Create(const Collection: TEnumerable<T>); overload;
destructor Destroy; override;
class procedure Error(const Msg: string; Data: NativeInt); overload; virtual;
{$IFNDEF NEXTGEN}
class procedure Error(Msg: PResStringRec; Data: NativeInt); overload;
{$ENDIF NEXTGEN}
function Add(const Value: T): Integer;
procedure AddRange(const Values: array of T); overload;
procedure AddRange(const Collection: IEnumerable<T>); overload;
procedure AddRange(const Collection: TEnumerable<T>); overload;
procedure Insert(Index: Integer; const Value: T);
procedure InsertRange(Index: Integer; const Values: array of T); overload;
procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;
procedure Pack; overload;
procedure Pack(const IsEmpty: TEmptyFunc); overload;
function Remove(const Value: T): Integer;
function RemoveItem(const Value: T; Direction: TDirection): Integer;
procedure Delete(Index: Integer);
procedure DeleteRange(AIndex, ACount: Integer);
function Extract(const Value: T): T;
function ExtractItem(const Value: T; Direction: TDirection): T;
procedure Exchange(Index1, Index2: Integer);
procedure Move(CurIndex, NewIndex: Integer);
function First: T;
function Last: T;
procedure Clear;
function Expand: TList<T>;
function Contains(const Value: T): Boolean;
function IndexOf(const Value: T): Integer;
function IndexOfItem(const Value: T; Direction: TDirection): Integer;
function LastIndexOf(const Value: T): Integer;
procedure Reverse;
procedure Sort; overload;
procedure Sort(const AComparer: IComparer<T>); overload;
function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;
function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;
procedure TrimExcess;
function ToArray: TArray<T>; override; final;
property Capacity: Integer read GetCapacity write SetCapacity;
property Count: Integer read FCount write SetCount;
property Items[Index: Integer]: T read GetItem write SetItem; default;
property List: arrayofT read FItems;
property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
type
TEnumerator = class(TEnumerator<T>)
private
FList: TList<T>;
FIndex: Integer;
function GetCurrent: T;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const AList: TList<T>);
property Current: T read GetCurrent;
function MoveNext: Boolean;
end;
function GetEnumerator: TEnumerator; reintroduce;
end;
TThreadList<T> = class
private
FList: TList<T>;
FLock: TObject;
FDuplicates: TDuplicates;
public
constructor Create;
destructor Destroy; override;
procedure Add(const Item: T);
procedure Clear;
function LockList: TList<T>;
procedure Remove(const Item: T); inline;
procedure RemoveItem(const Item: T; Direction: TDirection);
procedure UnlockList; inline;
property Duplicates: TDuplicates read FDuplicates write FDuplicates;
end;
// Queue implemented over array, using wrapping.
TQueue<T> = class(TEnumerable<T>)
private
FHead: Integer;
FTail: Integer;
FCount: Integer;
FItems: array of T;
FOnNotify: TCollectionNotifyEvent<T>;
FArrayManager: TArrayManager<T>;
procedure Grow;
procedure SetCapacity(Value: Integer);
function DoDequeue(Notification: TCollectionNotification): T;
procedure DoSetCapacity(Value: Integer);
function GetCapacity: Integer;
protected
function DoGetEnumerator: TEnumerator<T>; override;
procedure Notify(const Item: T; Action: TCollectionNotification); virtual;
public
constructor Create; overload;
constructor Create(const Collection: TEnumerable<T>); overload;
destructor Destroy; override;
procedure Enqueue(const Value: T);
function Dequeue: T;
function Extract: T;
function Peek: T;
procedure Clear;
procedure TrimExcess;
property Count: Integer read FCount;
property Capacity: Integer read GetCapacity write DoSetCapacity;
property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
function ToArray: TArray<T>; override; final;
type
TEnumerator = class(TEnumerator<T>)
private
FQueue: TQueue<T>;
FIndex: Integer;
function GetCurrent: T;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const AQueue: TQueue<T>);
property Current: T read GetCurrent;
function MoveNext: Boolean;
end;
function GetEnumerator: TEnumerator; reintroduce;
end;
TStack<T> = class(TEnumerable<T>)
private
FCount: Integer;
FItems: array of T;
FOnNotify: TCollectionNotifyEvent<T>;
procedure Grow;
function DoPop(Notification: TCollectionNotification): T;
procedure DoSetCapacity(Value: Integer);
function GetCapacity: Integer;
protected
function DoGetEnumerator: TEnumerator<T>; override;
procedure Notify(const Item: T; Action: TCollectionNotification); virtual;
public
constructor Create(const Collection: TEnumerable<T>); overload;
destructor Destroy; override;
procedure Clear;
procedure Push(const Value: T);
function Pop: T;
function Peek: T;
function Extract: T;
procedure TrimExcess;
function ToArray: TArray<T>; override; final;
property Count: Integer read FCount;
property Capacity: Integer read GetCapacity write DoSetCapacity;
property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
type
TEnumerator = class(TEnumerator<T>)
private
FStack: TStack<T>;
FIndex: Integer;
function GetCurrent: T;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const AStack: TStack<T>);
property Current: T read GetCurrent;
function MoveNext: Boolean;
end;
function GetEnumerator: TEnumerator; reintroduce;
end;
TPair<TKey,TValue> = record
Key: TKey;
Value: TValue;
constructor Create(const AKey: TKey; const AValue: TValue);
end;
// Hash table using linear probing
TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)
private
type
TItem = record
HashCode: Integer;
Key: TKey;
Value: TValue;
end;
TItemArray = array of TItem;
private
FItems: TItemArray;
FCount: Integer;
FComparer: IEqualityComparer<TKey>;
FGrowThreshold: Integer;
procedure SetCapacity(ACapacity: Integer);
procedure Rehash(NewCapPow2: Integer);
procedure Grow;
function GetBucketIndex(const Key: TKey; HashCode: Integer): Integer;
function Hash(const Key: TKey): Integer;
function GetItem(const Key: TKey): TValue;
procedure SetItem(const Key: TKey; const Value: TValue);
procedure RehashAdd(HashCode: Integer; const Key: TKey; const Value: TValue);
procedure DoAdd(HashCode, Index: Integer; const Key: TKey; const Value: TValue);
procedure DoSetValue(Index: Integer; const Value: TValue);
function DoRemove(const Key: TKey; HashCode: Integer; Notification: TCollectionNotification): TValue;
protected
function DoGetEnumerator: TEnumerator<TPair<TKey,TValue>>; override;
procedure KeyNotify(const Key: TKey; Action: TCollectionNotification); virtual;
procedure ValueNotify(const Value: TValue; Action: TCollectionNotification); virtual;
public
constructor Create(ACapacity: Integer = 0); overload;
constructor Create(const AComparer: IEqualityComparer<TKey>); overload;
constructor Create(ACapacity: Integer; const AComparer: IEqualityComparer<TKey>); overload;
constructor Create(const Collection: TEnumerable<TPair<TKey,TValue>>); overload;
constructor Create(const Collection: TEnumerable<TPair<TKey,TValue>>; const AComparer: IEqualityComparer<TKey>); overload;
destructor Destroy; override;
procedure Add(const Key: TKey; const Value: TValue);
procedure Remove(const Key: TKey);
function ExtractPair(const Key: TKey): TPair<TKey,TValue>;
procedure Clear;
procedure TrimExcess;
function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
procedure AddOrSetValue(const Key: TKey; const Value: TValue);
function ContainsKey(const Key: TKey): Boolean;
function ContainsValue(const Value: TValue): Boolean;
function ToArray: TArray<TPair<TKey,TValue>>; override; final;
property Items[const Key: TKey]: TValue read GetItem write SetItem; default;
property Count: Integer read FCount;
type
TPairEnumerator = class(TEnumerator<TPair<TKey,TValue>>)
private
FDictionary: TDictionary<TKey,TValue>;
FIndex: Integer;
function GetCurrent: TPair<TKey,TValue>;
protected
function DoGetCurrent: TPair<TKey,TValue>; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
property Current: TPair<TKey,TValue> read GetCurrent;
function MoveNext: Boolean;
end;
TKeyEnumerator = class(TEnumerator<TKey>)
private
FDictionary: TDictionary<TKey,TValue>;
FIndex: Integer;
function GetCurrent: TKey;
protected
function DoGetCurrent: TKey; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
property Current: TKey read GetCurrent;
function MoveNext: Boolean;
end;
TValueEnumerator = class(TEnumerator<TValue>)
private
FDictionary: TDictionary<TKey,TValue>;
FIndex: Integer;
function GetCurrent: TValue;
protected
function DoGetCurrent: TValue; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
property Current: TValue read GetCurrent;
function MoveNext: Boolean;
end;
TValueCollection = class(TEnumerable<TValue>)
private
[Weak] FDictionary: TDictionary<TKey,TValue>;
function GetCount: Integer;
protected
function DoGetEnumerator: TEnumerator<TValue>; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
function GetEnumerator: TValueEnumerator; reintroduce;
function ToArray: TArray<TValue>; override; final;
property Count: Integer read GetCount;
end;
TKeyCollection = class(TEnumerable<TKey>)
private
[Weak] FDictionary: TDictionary<TKey,TValue>;
function GetCount: Integer;
protected
function DoGetEnumerator: TEnumerator<TKey>; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
function GetEnumerator: TKeyEnumerator; reintroduce;
function ToArray: TArray<TKey>; override; final;
property Count: Integer read GetCount;
end;
private
FOnKeyNotify: TCollectionNotifyEvent<TKey>;
FOnValueNotify: TCollectionNotifyEvent<TValue>;
FKeyCollection: TKeyCollection;
FValueCollection: TValueCollection;
function GetKeys: TKeyCollection;
function GetValues: TValueCollection;
public
function GetEnumerator: TPairEnumerator; reintroduce;
property Keys: TKeyCollection read GetKeys;
property Values: TValueCollection read GetValues;
property OnKeyNotify: TCollectionNotifyEvent<TKey> read FOnKeyNotify write FOnKeyNotify;
property OnValueNotify: TCollectionNotifyEvent<TValue> read FOnValueNotify write FOnValueNotify;
end;
TObjectList<T: class> = class(TList<T>)
private
FOwnsObjects: Boolean;
protected
procedure Notify(const Value: T; Action: TCollectionNotification); override;
public
constructor Create(AOwnsObjects: Boolean = True); overload;
constructor Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean = True); overload;
constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
end;
TObjectQueue<T: class> = class(TQueue<T>)
private
FOwnsObjects: Boolean;
protected
procedure Notify(const Value: T; Action: TCollectionNotification); override;
public
constructor Create(AOwnsObjects: Boolean = True); overload;
constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
procedure Dequeue;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
end;
TObjectStack<T: class> = class(TStack<T>)
private
FOwnsObjects: Boolean;
protected
procedure Notify(const Value: T; Action: TCollectionNotification); override;
public
constructor Create(AOwnsObjects: Boolean = True); overload;
constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
procedure Pop;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
end;
TDictionaryOwnerships = set of (doOwnsKeys, doOwnsValues);
TObjectDictionary<TKey,TValue> = class(TDictionary<TKey,TValue>)
private
FOwnerships: TDictionaryOwnerships;
protected
procedure KeyNotify(const Key: TKey; Action: TCollectionNotification); override;
procedure ValueNotify(const Value: TValue; Action: TCollectionNotification); override;
public
constructor Create(Ownerships: TDictionaryOwnerships; ACapacity: Integer = 0); overload;
constructor Create(Ownerships: TDictionaryOwnerships;
const AComparer: IEqualityComparer<TKey>); overload;
constructor Create(Ownerships: TDictionaryOwnerships; ACapacity: Integer;
const AComparer: IEqualityComparer<TKey>); overload;
end;
TThreadedQueue<T> = class
private
FQueue: array of T;
FQueueSize, FQueueOffset: Integer;
FQueueNotEmpty,
FQueueNotFull: TObject;
FQueueLock: TObject;
FShutDown: Boolean;
FPushTimeout, FPopTimeout: LongWord;
FTotalItemsPushed, FTotalItemsPopped: LongWord;
public
constructor Create(AQueueDepth: Integer = 10; PushTimeout: LongWord = INFINITE; PopTimeout: LongWord = INFINITE);
destructor Destroy; override;
procedure Grow(ADelta: Integer);
function PushItem(const AItem: T): TWaitResult; overload;
function PushItem(const AItem: T; var AQueueSize: Integer): TWaitResult; overload;
function PopItem: T; overload;
function PopItem(var AQueueSize: Integer): T; overload;
function PopItem(var AQueueSize: Integer; var AItem: T): TWaitResult; overload;
function PopItem(var AItem: T): TWaitResult; overload;
procedure DoShutDown;
property QueueSize: Integer read FQueueSize;
property ShutDown: Boolean read FShutDown;
property TotalItemsPushed: LongWord read FTotalItemsPushed;
property TotalItemsPopped: LongWord read FTotalItemsPopped;
end;
PObject = ^TObject;
function InCircularRange(Bottom, Item, TopInc: Integer): Boolean; inline;
implementation
uses System.TypInfo, System.SysConst, System.RTLConsts;
{ TArray }
class function TArray.BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>; Index,
Count: Integer): Boolean;
var
L, H: Integer;
mid, cmp: Integer;
begin
if (Index < Low(Values)) or ((Index > High(Values)) and (Count > 0))
or (Index + Count - 1 > High(Values)) or (Count < 0)
or (Index + Count < 0) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if Count = 0 then
begin
FoundIndex := Index;
Exit(False);
end;
Result := False;
L := Index;
H := Index + Count - 1;
while L <= H do
begin
mid := L + (H - L) shr 1;
cmp := Comparer.Compare(Values[mid], Item);
if cmp < 0 then
L := mid + 1
else
begin
H := mid - 1;
if cmp = 0 then
Result := True;
end;
end;
FoundIndex := L;
end;
class function TArray.BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>): Boolean;
begin
Result := BinarySearch<T>(Values, Item, FoundIndex, Comparer,
Low(Values), Length(Values));
end;
class function TArray.BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer): Boolean;
begin
Result := BinarySearch<T>(Values, Item, FoundIndex, TComparer<T>.Default,
Low(Values), Length(Values));
end;
class procedure TArray.Copy<T>(const Source, Destination: array of T; SourceIndex, DestIndex, Count: NativeInt);
begin
CheckArrays(PPointer(@Source)^, PPointer(@Destination)^, SourceIndex, Length(Source), DestIndex, Length(Destination), Count);
System.CopyArray(Pointer(@Destination[SourceIndex]), Pointer(@Source[SourceIndex]), TypeInfo(T), Count);
end;
class procedure TArray.CheckArrays(Source, Destination: Pointer; SourceIndex, SourceLength, DestIndex, DestLength, Count: NativeInt);
begin
if (SourceIndex < 0) or (DestIndex < 0) or (SourceIndex >= SourceLength) or (DestIndex >= DestLength) or
(SourceIndex + Count >= SourceLength) or (DestIndex + Count >= DestLength) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if Source = Destination then
raise EArgumentException.CreateRes(@sSameArrays);
end;
class procedure TArray.Copy<T>(const Source, Destination: array of T; Count: NativeInt);
begin
Copy(Source, Destination, 0, 0, Count);
end;
class procedure TArray.QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>;
L, R: Integer);
var
I, J: Integer;
pivot, temp: T;
begin
if (Length(Values) = 0) or ((R - L) <= 0) then
Exit;
repeat
I := L;
J := R;
pivot := Values[L + (R - L) shr 1];
repeat
while Comparer.Compare(Values[I], pivot) < 0 do
Inc(I);
while Comparer.Compare(Values[J], pivot) > 0 do
Dec(J);
if I <= J then
begin
if I <> J then
begin
temp := Values[I];
Values[I] := Values[J];
Values[J] := temp;
end;
Inc(I);
Dec(J);
end;
until I > J;
if L < J then
QuickSort<T>(Values, Comparer, L, J);
L := I;
until I >= R;
end;
class procedure TArray.Sort<T>(var Values: array of T);
begin
QuickSort<T>(Values, TComparer<T>.Default, Low(Values), High(Values));
end;
class procedure TArray.Sort<T>(var Values: array of T; const Comparer: IComparer<T>);
begin
QuickSort<T>(Values, Comparer, Low(Values), High(Values));
end;
class procedure TArray.Sort<T>(var Values: array of T; const Comparer: IComparer<T>;
Index, Count: Integer);
begin
if (Index < Low(Values)) or ((Index > High(Values)) and (Count > 0))
or (Index + Count - 1 > High(Values)) or (Count < 0)
or (Index + Count < 0) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if Count <= 1 then
Exit;
QuickSort<T>(Values, Comparer, Index, Index + Count - 1);
end;
{ TEnumerator<T> }
function TEnumerator<T>.MoveNext: Boolean;
begin
Result := DoMoveNext;
end;
{ TEnumerable<T> }
// The overridden destructor that simply invokes 'inherited' is
// required to instantiate the destructor for C++ code
destructor TEnumerable<T>.Destroy;
begin
inherited;
end;
function TEnumerable<T>.GetEnumerator: TEnumerator<T>;
begin
Result := DoGetEnumerator;
end;
function TEnumerable<T>.ToArray: TArray<T>;
var
buf: TList<T>;
x: T;
begin
buf := TList<T>.Create;
try
for x in Self do
buf.Add(x);
Result := buf.ToArray; // relies on TList<T>.ToArray override
finally
buf.Free;
end;
end;
function TEnumerable<T>.ToArrayImpl(Count: Integer): TArray<T>;
var
x: T;
begin
// We assume our caller has passed correct Count
SetLength(Result, Count);
Count := 0;
for x in Self do
begin
Result[Count] := x;
Inc(Count);
end;
end;
{ TList<T> }
function TList<T>.GetCapacity: Integer;
begin
Result := Length(FItems); //3)디버깅 해보면 오류메새지가 여기서 나는것 같습니다
end;
procedure TList<T>.SetCapacity(Value: Integer);
begin
if Value < Count then
Count := Value;
SetLength(FItems, Value);
end;
procedure TList<T>.SetCount(Value: Integer);
begin
if Value < 0 then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if Value > Capacity then
SetCapacity(Value);
if Value < Count then
DeleteRange(Value, Count - Value);
FCount := Value;
end;
function TList<T>.GetItem(Index: Integer): T;
begin
if (Index < 0) or (Index >= Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
Result := FItems[Index];
end;
procedure TList<T>.SetItem(Index: Integer; const Value: T);
var
oldItem: T;
begin
if (Index < 0) or (Index >= Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
oldItem := FItems[Index];
FItems[Index] := Value;
Notify(oldItem, cnRemoved);
Notify(Value, cnAdded);
end;
procedure TList<T>.Grow(ACount: Integer);
var
newCount: Integer;
begin
newCount := Length(FItems);
if newCount = 0 then
newCount := ACount
else
repeat
newCount := newCount * 2;
if newCount < 0 then
OutOfMemoryError;
until newCount >= ACount;
Capacity := newCount;
end;
procedure TList<T>.GrowCheck(ACount: Integer);
begin
if ACount > Length(FItems) then
Grow(ACount)
else if ACount < 0 then
OutOfMemoryError;
end;
procedure TList<T>.Notify(const Item: T; Action: TCollectionNotification);
begin
if Assigned(FOnNotify) then
FOnNotify(Self, Item, Action);
end;
procedure TList<T>.Pack;
begin
Pack(function (const Left, Right: T): Boolean
begin
Result := FComparer.Compare(Left, Right) = 0;
end);
end;
procedure TList<T>.Pack(const IsEmpty: TEmptyFunc);
var
PackedCount : Integer;
StartIndex : Integer;
EndIndex : Integer;
begin
if FCount = 0 then
Exit;
PackedCount := 0;
StartIndex := 0;
repeat
// Locate the first/next non-nil element in the list
// while (StartIndex < FCount) and (FComparer.Compare(FItems[StartIndex], Default(T)) = 0) do
while (StartIndex < FCount) and (IsEmpty(FItems[StartIndex], Default(T))) do
Inc(StartIndex);
if StartIndex < FCount then // There is nothing more to do
begin
// Locate the next nil pointer
EndIndex := StartIndex;
// while (EndIndex < FCount) and (FComparer.Compare(FItems[EndIndex], Default(T)) <> 0) do
while (EndIndex < FCount) and not IsEmpty(FItems[EndIndex], Default(T)) do
Inc(EndIndex);
Dec(EndIndex);
// Move this block of non-null items to the index recorded in PackedToCount:
// If this is a contiguous non-nil block at the start of the list then
// StartIndex and PackedToCount will be equal (and 0) so don't bother with the move.
if StartIndex > PackedCount then
FArrayManager.Move(FItems, StartIndex, PackedCount, EndIndex - StartIndex + 1);
// Set the PackedToCount to reflect the number of items in the list
// that have now been packed.
Inc(PackedCount, EndIndex - StartIndex + 1);
// Reset StartIndex to the element following EndIndex
StartIndex := EndIndex + 1;
end;
until StartIndex >= FCount;
// Set Count so that the 'free' item
FCount := PackedCount;
end;
constructor TList<T>.Create;
begin
Create(TComparer<T>.Default);
end;
constructor TList<T>.Create(const AComparer: IComparer<T>);
begin
inherited Create;
{$IF Defined(WEAKREF)}
if System.HasWeakRef(T) then
FArrayManager := TManualArrayManager<T>.Create
else
{$ENDIF}
FArrayManager := TMoveArrayManager<T>.Create;
FComparer := AComparer;
if FComparer = nil then
FComparer := TComparer<T>.Default;
end;
constructor TList<T>.Create(const Collection: TEnumerable<T>);
begin
inherited Create;
{$IF Defined(WEAKREF)}
if System.HasWeakRef(T) then
FArrayManager := TManualArrayManager<T>.Create
else
{$ENDIF}
FArrayManager := TMoveArrayManager<T>.Create;
FComparer := TComparer<T>.Default;
InsertRange(0, Collection);
end;
destructor TList<T>.Destroy;
begin
Capacity := 0;
FArrayManager.Free;
inherited;
end;
class procedure TList<T>.Error(const Msg: string; Data: NativeInt);
begin
raise EListError.CreateFmt(Msg, [Data]) at ReturnAddress;
end;
{$IFNDEF NEXTGEN}
class procedure TList<T>.Error(Msg: PResStringRec; Data: NativeInt);
begin
raise EListError.CreateFmt(LoadResString(Msg), [Data]) at ReturnAddress;
end;
{$ENDIF NEXTGEN}
function TList<T>.DoGetEnumerator: TEnumerator<T>;
begin
Result := GetEnumerator;
end;
function TList<T>.Add(const Value: T): Integer;
begin
GrowCheck(Count + 1);
Result := Count;
FItems[Count] := Value;
Inc(FCount);
Notify(Value, cnAdded);
end;
procedure TList<T>.AddRange(const Values: array of T);
begin
InsertRange(Count, Values);
end;
procedure TList<T>.AddRange(const Collection: IEnumerable<T>);
begin
InsertRange(Count, Collection);
end;
procedure TList<T>.AddRange(const Collection: TEnumerable<T>);
begin
InsertRange(Count, Collection);
end;
function TList<T>.BinarySearch(const Item: T; out Index: Integer): Boolean;
begin
Result := TArray.BinarySearch<T>(FItems, Item, Index, FComparer, 0, Count);
end;
function TList<T>.BinarySearch(const Item: T; out Index: Integer;
const AComparer: IComparer<T>): Boolean;
begin
Result := TArray.BinarySearch<T>(FItems, Item, Index, AComparer, 0, Count);
end;
procedure TList<T>.Insert(Index: Integer; const Value: T);
begin
if (Index < 0) or (Index > Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
GrowCheck(Count + 1);
if Index <> Count then
begin
FArrayManager.Move(FItems, Index, Index + 1, Count - Index);
FArrayManager.Finalize(FItems, Index, 1);
end;
FItems[Index] := Value;
Inc(FCount);
Notify(Value, cnAdded);
end;
procedure TList<T>.InsertRange(Index: Integer; const Values: array of T);
var
I: Integer;
begin
if (Index < 0) or (Index > Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
GrowCheck(Count + Length(Values));
if Index <> Count then
begin
FArrayManager.Move(FItems, Index, Index + Length(Values), Count - Index);
FArrayManager.Finalize(FItems, Index, Length(Values));
end;
for I := 0 to Length(Values) - 1 do
FItems[Index + I] := Values[I];
Inc(FCount, Length(Values));
for I := 0 to Length(Values) - 1 do
Notify(Values[I], cnAdded);
end;
procedure TList<T>.InsertRange(Index: Integer; const Collection: IEnumerable<T>);
var
item: T;
begin
for item in Collection do
begin
Insert(Index, item);
Inc(Index);
end;
end;
procedure TList<T>.InsertRange(Index: Integer; const Collection: TEnumerable<T>);
var
item: T;
begin
for item in Collection do
begin
Insert(Index, item);
Inc(Index);
end;
end;
function TList<T>.ItemValue(const Item: T): NativeInt;
begin
case SizeOf(Item) of
1: Result := PByte(@Item)[0] shl 0;
2: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8;
3: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16;
{$IF SizeOf(IntPtr) <= 4}
else
Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24;
{$ELSE}
4: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24;
5: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24 +
IntPtr(PByte(@Item)[4]) shl 32;
6: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24 +
IntPtr(PByte(@Item)[4]) shl 32 + IntPtr(PByte(@Item)[5]) shl 40;
7: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24 +
IntPtr(PByte(@Item)[4]) shl 32 + IntPtr(PByte(@Item)[5]) shl 40 + IntPtr(PByte(@Item)[6]) shl 48;
else
Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24 +
IntPtr(PByte(@Item)[4]) shl 32 + IntPtr(PByte(@Item)[5]) shl 40 + IntPtr(PByte(@Item)[6]) shl 48 + IntPtr(PByte(@Item)[7]) shl 56;
{$ENDIF}
end;
end;
procedure TList<T>.Exchange(Index1, Index2: Integer);
var
temp: T;
begin
temp := FItems[Index1];
FItems[Index1] := FItems[Index2];
FItems[Index2] := temp;
end;
function TList<T>.Extract(const Value: T): T;
begin
Result := ExtractItem(Value, TDirection.FromBeginning);
end;
function TList<T>.ExtractItem(const Value: T; Direction: TDirection): T;
var
index: Integer;
begin
index := IndexOfItem(Value, Direction);
if index < 0 then
Result := Default(T)
else
begin
Result := FItems[index];
DoDelete(index, cnExtracted);
end;
end;
function TList<T>.First: T;
begin
Result := Items[0];
end;
function TList<T>.Remove(const Value: T): Integer;
begin
Result := IndexOf(Value);
if Result >= 0 then
Delete(Result);
end;
function TList<T>.RemoveItem(const Value: T; Direction: TDirection): Integer;
begin
Result := IndexOfItem(Value, Direction);
if Result >= 0 then
Delete(Result);
end;
procedure TList<T>.DoDelete(Index: Integer; Notification: TCollectionNotification);
var
oldItem: T;
begin
if (Index < 0) or (Index >= Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
oldItem := FItems[Index];
FItems[Index] := Default(T);
Dec(FCount);
if Index <> Count then
begin
FArrayManager.Move(FItems, Index + 1, Index, Count - Index);
FArrayManager.Finalize(FItems, Count, 1);
end;
Notify(oldItem, Notification);
end;
procedure TList<T>.Delete(Index: Integer);
begin
DoDelete(Index, cnRemoved);
end;
procedure TList<T>.DeleteRange(AIndex, ACount: Integer);
var
oldItems: array of T;
tailCount, I: Integer;
begin
if (AIndex < 0) or (ACount < 0) or (AIndex + ACount > Count)
or (AIndex + ACount < 0) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if ACount = 0 then
Exit;
SetLength(oldItems, ACount);
FArrayManager.Move(FItems, oldItems, AIndex, 0, ACount);
tailCount := Count - (AIndex + ACount);
if tailCount > 0 then
begin
FArrayManager.Move(FItems, AIndex + ACount, AIndex, tailCount);
FArrayManager.Finalize(FItems, Count - ACount, ACount);
end else
FArrayManager.Finalize(FItems, AIndex, ACount);
Dec(FCount, ACount);
for I := 0 to Length(oldItems) - 1 do
Notify(oldItems[I], cnRemoved);
end;
procedure TList<T>.Clear;
begin
Count := 0;
Capacity := 0;
end;
function TList<T>.Expand: TList<T>;
begin
if FCount = Length(FItems) then
GrowCheck(FCount + 1);
Result := Self;
end;
function TList<T>.Contains(const Value: T): Boolean;
begin
Result := IndexOf(Value) >= 0;
end;
function TList<T>.IndexOf(const Value: T): Integer;
var
i: Integer;
begin
for i := 0 to Count - 1 do
if FComparer.Compare(FItems[i], Value) = 0 then
Exit(i);
Result := -1;
end;
function TList<T>.IndexOfItem(const Value: T; Direction: TDirection): Integer;
var
P: T;
i: Integer;
begin
if Direction = TDirection.FromBeginning then
Result := IndexOf(Value)
else
begin
if Count > 0 then
begin
for i := Count - 1 downto 0 do
if FComparer.Compare(FItems[i], Value) = 0 then
Exit(i);
end;
Result := -1;
end;
end;
function TList<T>.Last: T;
begin
Result := Items[Count - 1];
end;
function TList<T>.LastIndexOf(const Value: T): Integer;
var
i: Integer;
begin
for i := Count - 1 downto 0 do
if FComparer.Compare(FItems[i], Value) = 0 then
Exit(i);
Result := -1;
end;
procedure TList<T>.Move(CurIndex, NewIndex: Integer);
var
temp: T;
begin
if CurIndex = NewIndex then
Exit;
if (NewIndex < 0) or (NewIndex >= FCount) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
temp := FItems[CurIndex];
FItems[CurIndex] := Default(T);
if CurIndex < NewIndex then
FArrayManager.Move(FItems, CurIndex + 1, CurIndex, NewIndex - CurIndex)
else
FArrayManager.Move(FItems, NewIndex, NewIndex + 1, CurIndex - NewIndex);
FArrayManager.Finalize(FItems, NewIndex, 1);
FItems[NewIndex] := temp;
end;
procedure TList<T>.Reverse;
var
tmp: T;
b, e: Integer;
begin
b := 0;
e := Count - 1;
while b < e do
begin
tmp := FItems[b];
FItems[b] := FItems[e];
FItems[e] := tmp;
Inc(b);
Dec(e);
end;
end;
procedure TList<T>.Sort;
begin
TArray.Sort<T>(FItems, FComparer, 0, Count);
end;
procedure TList<T>.Sort(const AComparer: IComparer<T>);
begin
TArray.Sort<T>(FItems, AComparer, 0, Count);
end;
function TList<T>.ToArray: TArray<T>;
var
i: Integer;
begin
SetLength(Result, Count);
for i := 0 to Count - 1 do
Result[i] := Items[i];
end;
procedure TList<T>.TrimExcess;
begin
Capacity := Count;
end;
function TList<T>.GetEnumerator: TEnumerator;
begin
Result := TEnumerator.Create(Self);
end;
{ TList<T>.TEnumerator }
constructor TList<T>.TEnumerator.Create(const AList: TList<T>);
begin
inherited Create;
FList := AList;
FIndex := -1;
end;
function TList<T>.TEnumerator.DoGetCurrent: T;
begin
Result := GetCurrent;
end;
function TList<T>.TEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;
function TList<T>.TEnumerator.GetCurrent: T;
begin
Result := FList[FIndex];
end;
function TList<T>.TEnumerator.MoveNext: Boolean;
begin
if FIndex >= FList.Count then
Exit(False);
Inc(FIndex);
Result := FIndex < FList.Count;
end;
{ TQueue<T> }
procedure TQueue<T>.Notify(const Item: T; Action: TCollectionNotification);
begin
if Assigned(FOnNotify) then
FOnNotify(Self, Item, Action);
end;
constructor TQueue<T>.Create;
begin
inherited Create;
{$IF Defined(WEAKREF)}
if System.HasWeakRef(T) then
FArrayManager := TManualArrayManager<T>.Create
else
{$ENDIF}
FArrayManager := TMoveArrayManager<T>.Create;
end;
function TQueue<T>.Dequeue: T;
begin
Result := DoDequeue(cnRemoved);
end;
destructor TQueue<T>.Destroy;
begin
Clear;
FArrayManager.Free;
inherited;
end;
function TQueue<T>.DoGetEnumerator: TEnumerator<T>;
begin
Result := GetEnumerator;
end;
procedure TQueue<T>.DoSetCapacity(Value: Integer);
begin
if Value < Count then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
SetCapacity(Value);
end;
procedure TQueue<T>.Enqueue(const Value: T);
begin
if Count = Length(FItems) then
Grow;
FItems[FHead] := Value;
FHead := (FHead + 1) mod Length(FItems);
Inc(FCount);
Notify(Value, cnAdded);
end;
function TQueue<T>.Extract: T;
begin
Result := DoDequeue(cnExtracted);
end;
constructor TQueue<T>.Create(const Collection: TEnumerable<T>);
var
item: T;
begin
inherited Create;
{$IF Defined(WEAKREF)}
if System.HasWeakRef(T) then
FArrayManager := TManualArrayManager<T>.Create
else
{$ENDIF}
FArrayManager := TMoveArrayManager<T>.Create;
for item in Collection do
Enqueue(item);
end;
function TQueue<T>.DoDequeue(Notification: TCollectionNotification): T;
begin
if Count = 0 then
raise EListError.CreateRes(@SUnbalancedOperation);
Result := FItems[FTail];
FItems[FTail] := Default(T);
FTail := (FTail + 1) mod Length(FItems);
Dec(FCount);
Notify(Result, Notification);
end;
function TQueue<T>.Peek: T;
begin
if Count = 0 then
raise EListError.CreateRes(@SUnbalancedOperation);
Result := FItems[FTail];
end;
procedure TQueue<T>.Clear;
begin
while Count > 0 do
Dequeue;
FHead := 0;
FTail := 0;
FCount := 0;
end;
function TQueue<T>.ToArray: TArray<T>;
begin
Result := ToArrayImpl(Count);
end;
procedure TQueue<T>.TrimExcess;
begin
SetCapacity(Count);
end;
procedure TQueue<T>.SetCapacity(Value: Integer);
var
tailCount, offset: Integer;
begin
offset := Value - Length(FItems);
if offset = 0 then
Exit;
// If head <= tail, then part of the queue wraps around
// the end of the array; don't introduce a gap in the queue.
if (FHead < FTail) or ((FHead = FTail) and (Count > 0)) then
tailCount := Length(FItems) - FTail
else
tailCount := 0;
if offset > 0 then
SetLength(FItems, Value);
if tailCount > 0 then
begin
FArrayManager.Move(FItems, FTail, FTail + offset, tailCount);
if offset > 0 then
FArrayManager.Finalize(FItems, FTail, offset)
else if offset < 0 then
FArrayManager.Finalize(FItems, Count, (- offset));
Inc(FTail, offset);
end
else if FTail > 0 then
begin
if Count > 0 then
begin
FArrayManager.Move(FItems, FTail, 0, Count);
FArrayManager.Finalize(FItems, FCount, FTail);
end;
Dec(FHead, FTail);
FTail := 0;
end;
if offset < 0 then
begin
SetLength(FItems, Value);
if Value = 0 then
FHead := 0
else
FHead := FHead mod Length(FItems);
end;
end;
procedure TQueue<T>.Grow;
var
newCap: Integer;
begin
newCap := Length(FItems) * 2;
if newCap = 0 then
newCap := 4
else if newCap < 0 then
OutOfMemoryError;
SetCapacity(newCap);
end;
function TQueue<T>.GetCapacity: Integer;
begin
Result := Length(FItems);
end;
function TQueue<T>.GetEnumerator: TEnumerator;
begin
Result := TEnumerator.Create(Self);
end;
{ TQueue<T>.TEnumerator }
constructor TQueue<T>.TEnumerator.Create(const AQueue: TQueue<T>);
begin
inherited Create;
FQueue := AQueue;
FIndex := -1;
end;
function TQueue<T>.TEnumerator.DoGetCurrent: T;
begin
Result := GetCurrent;
end;
function TQueue<T>.TEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;
function TQueue<T>.TEnumerator.GetCurrent: T;
begin
Result := FQueue.FItems[(FQueue.FTail + FIndex) mod Length(FQueue.FItems)];
end;
function TQueue<T>.TEnumerator.MoveNext: Boolean;
begin
if FIndex >= FQueue.Count then
Exit(False);
Inc(FIndex);
Result := FIndex < FQueue.Count;
end;
{ TStack<T> }
procedure TStack<T>.Notify(const Item: T; Action: TCollectionNotification);
begin
if Assigned(FOnNotify) then
FOnNotify(Self, Item, Action);
end;
constructor TStack<T>.Create(const Collection: TEnumerable<T>);
var
item: T;
begin
inherited Create;
for item in Collection do
Push(item);
end;
destructor TStack<T>.Destroy;
begin
Clear;
inherited;
end;
function TStack<T>.DoGetEnumerator: TEnumerator<T>;
begin
Result := GetEnumerator;
end;
procedure TStack<T>.Grow;
var
newCap: Integer;
begin
newCap := Length(FItems) * 2;
if newCap = 0 then
newCap := 4
else if newCap < 0 then
OutOfMemoryError;
SetLength(FItems, newCap);
end;
procedure TStack<T>.Push(const Value: T);
begin
if Count = Length(FItems) then
Grow;
FItems[Count] := Value;
Inc(FCount);
Notify(Value, cnAdded);
end;
function TStack<T>.DoPop(Notification: TCollectionNotification): T;
begin
if Count = 0 then
raise EListError.CreateRes(@SUnbalancedOperation);
Dec(FCount);
Result := FItems[Count];
FItems[Count] := Default(T);
Notify(Result, Notification);
end;
procedure TStack<T>.DoSetCapacity(Value: Integer);
begin
if Value < Count then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
SetLength(FItems, Value);
end;
function TStack<T>.Extract: T;
begin
Result := DoPop(cnExtracted);
end;
function TStack<T>.Peek: T;
begin
if Count = 0 then
raise EListError.CreateRes(@SUnbalancedOperation);
Result := FItems[Count - 1];
end;
function TStack<T>.Pop: T;
begin
Result := DoPop(cnRemoved);
end;
procedure TStack<T>.Clear;
begin
while Count > 0 do
Pop;
SetLength(FItems, 0);
end;
function TStack<T>.ToArray: TArray<T>;
begin
Result := ToArrayImpl(Count);
end;
procedure TStack<T>.TrimExcess;
begin
SetLength(FItems, Count);
end;
function TStack<T>.GetCapacity: Integer;
begin
Result := Length(FItems);
end;
function TStack<T>.GetEnumerator: TEnumerator;
begin
Result := TEnumerator.Create(Self);
end;
constructor TStack<T>.TEnumerator.Create(const AStack: TStack<T>);
begin
inherited Create;
FStack := AStack;
FIndex := -1;
end;
function TStack<T>.TEnumerator.DoGetCurrent: T;
begin
Result := GetCurrent;
end;
function TStack<T>.TEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;
function TStack<T>.TEnumerator.GetCurrent: T;
begin
Result := FStack.FItems[FIndex];
end;
function TStack<T>.TEnumerator.MoveNext: Boolean;
begin
if FIndex >= FStack.Count then
Exit(False);
Inc(FIndex);
Result := FIndex < FStack.Count;
end;
{ TPair<TKey,TValue> }
constructor TPair<TKey,TValue>.Create(const AKey: TKey; const AValue: TValue);
begin
Key := AKey;
Value := AValue;
end;
{ TDictionary<TKey,TValue> }
const
EMPTY_HASH = -1;
procedure TDictionary<TKey,TValue>.Rehash(NewCapPow2: Integer);
var
oldItems, newItems: TItemArray;
i: Integer;
begin
if NewCapPow2 = Length(FItems) then
Exit
else if NewCapPow2 < 0 then
OutOfMemoryError;
oldItems := FItems;
SetLength(newItems, NewCapPow2);
for i := 0 to Length(newItems) - 1 do
newItems[i].HashCode := EMPTY_HASH;
FItems := newItems;
FGrowThreshold := NewCapPow2 shr 1 + NewCapPow2 shr 2; // 75%
for i := 0 to Length(oldItems) - 1 do
if oldItems[i].HashCode <> EMPTY_HASH then
RehashAdd(oldItems[i].HashCode, oldItems[i].Key, oldItems[i].Value);
end;
procedure TDictionary<TKey,TValue>.SetCapacity(ACapacity: Integer);
var
newCap: Integer;
begin
if ACapacity < Count then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if ACapacity = 0 then
Rehash(0)
else
begin
newCap := 4;
while newCap < ACapacity do
newCap := newCap shl 1;
Rehash(newCap);
end
end;
procedure TDictionary<TKey,TValue>.Grow;
var
newCap: Integer;
begin
newCap := Length(FItems) * 2;
if newCap = 0 then
newCap := 4;
Rehash(newCap);
end;
function TDictionary<TKey,TValue>.GetBucketIndex(const Key: TKey; HashCode: Integer): Integer;
var
start, hc: Integer;
begin
if Length(FItems) = 0 then
Exit(not High(Integer));
start := HashCode and (Length(FItems) - 1);
Result := start;
while True do
begin
hc := FItems[Result].HashCode;
// Not found: return complement of insertion point.
if hc = EMPTY_HASH then
Exit(not Result);
// Found: return location.
if (hc = HashCode) and FComparer.Equals(FItems[Result].Key, Key) then
Exit(Result);
Inc(Result);
if Result >= Length(FItems) then
Result := 0;
end;
end;
function TDictionary<TKey,TValue>.Hash(const Key: TKey): Integer;
const
PositiveMask = not Integer($80000000);
begin
// Double-Abs to avoid -MaxInt and MinInt problems.
// Not using compiler-Abs because we *must* get a positive integer;
// for compiler, Abs(Low(Integer)) is a null op.
Result := PositiveMask and ((PositiveMask and FComparer.GetHashCode(Key)) + 1);
end;
function TDictionary<TKey,TValue>.GetItem(const Key: TKey): TValue;
var
index: Integer;
begin
index := GetBucketIndex(Key, Hash(Key));
if index < 0 then
raise EListError.CreateRes(@SGenericItemNotFound);
Result := FItems[index].Value;
end;
procedure TDictionary<TKey,TValue>.SetItem(const Key: TKey; const Value: TValue);
var
index: Integer;
oldValue: TValue;
begin
index := GetBucketIndex(Key, Hash(Key));
if index < 0 then
raise EListError.CreateRes(@SGenericItemNotFound);
oldValue := FItems[index].Value;
FItems[index].Value := Value;
ValueNotify(oldValue, cnRemoved);
ValueNotify(Value, cnAdded);
end;
procedure TDictionary<TKey,TValue>.RehashAdd(HashCode: Integer; const Key: TKey; const Value: TValue);
var
index: Integer;
begin
index := not GetBucketIndex(Key, HashCode);
FItems[index].HashCode := HashCode;
FItems[index].Key := Key;
FItems[index].Value := Value;
end;
procedure TDictionary<TKey,TValue>.KeyNotify(const Key: TKey; Action: TCollectionNotification);
begin
if Assigned(FOnKeyNotify) then
FOnKeyNotify(Self, Key, Action);
end;
procedure TDictionary<TKey,TValue>.ValueNotify(const Value: TValue; Action: TCollectionNotification);
begin
if Assigned(FOnValueNotify) then
FOnValueNotify(Self, Value, Action);
end;
constructor TDictionary<TKey,TValue>.Create(ACapacity: Integer = 0);
begin
Create(ACapacity, nil);
end;
constructor TDictionary<TKey,TValue>.Create(const AComparer: IEqualityComparer<TKey>);
begin
Create(0, AComparer);
end;
constructor TDictionary<TKey,TValue>.Create(ACapacity: Integer; const AComparer: IEqualityComparer<TKey>);
var
cap: Integer;
begin
inherited Create;
if ACapacity < 0 then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
FComparer := AComparer;
if FComparer = nil then
FComparer := TEqualityComparer<TKey>.Default;
SetCapacity(ACapacity);
end;
constructor TDictionary<TKey, TValue>.Create(const Collection: TEnumerable<TPair<TKey, TValue>>);
var
item: TPair<TKey,TValue>;
begin
Create(0, nil);
for item in Collection do
AddOrSetValue(item.Key, item.Value);
end;
constructor TDictionary<TKey, TValue>.Create(const Collection: TEnumerable<TPair<TKey, TValue>>;
const AComparer: IEqualityComparer<TKey>);
var
item: TPair<TKey,TValue>;
begin
Create(0, AComparer);
for item in Collection do
AddOrSetValue(item.Key, item.Value);
end;
destructor TDictionary<TKey,TValue>.Destroy;
begin
Clear;
FKeyCollection.Free;
FValueCollection.Free;
inherited;
end;
procedure TDictionary<TKey,TValue>.Add(const Key: TKey; const Value: TValue);
var
index, hc: Integer;
begin
if Count >= FGrowThreshold then
Grow;
hc := Hash(Key);
index := GetBucketIndex(Key, hc);
if index >= 0 then
raise EListError.CreateRes(@SGenericDuplicateItem);
DoAdd(hc, not index, Key, Value);
end;
function InCircularRange(Bottom, Item, TopInc: Integer): Boolean;
begin
Result := (Bottom < Item) and (Item <= TopInc) // normal
or (TopInc < Bottom) and (Item > Bottom) // top wrapped
or (TopInc < Bottom) and (Item <= TopInc) // top and item wrapped
end;
function TDictionary<TKey,TValue>.DoRemove(const Key: TKey; HashCode: Integer;
Notification: TCollectionNotification): TValue;
var
gap, index, hc, bucket: Integer;
begin
index := GetBucketIndex(Key, HashCode);
if index < 0 then
Exit(Default(TValue));
// Removing item from linear probe hash table is moderately
// tricky. We need to fill in gaps, which will involve moving items
// which may not even hash to the same location.
// Knuth covers it well enough in Vol III. 6.4.; but beware, Algorithm R
// (2nd ed) has a bug: step R4 should go to step R1, not R2 (already errata'd).
// My version does linear probing forward, not backward, however.
// gap refers to the hole that needs filling-in by shifting items down.
// index searches for items that have been probed out of their slot,
// but being careful not to move items if their bucket is between
// our gap and our index (so that they'd be moved before their bucket).
// We move the item at index into the gap, whereupon the new gap is
// at the index. If the index hits a hole, then we're done.
// If our load factor was exactly 1, we'll need to hit this hole
// in order to terminate. Shouldn't normally be necessary, though.
FItems[index].HashCode := EMPTY_HASH;
Result := FItems[index].Value;
gap := index;
while True do
begin
Inc(index);
if index = Length(FItems) then
index := 0;
hc := FItems[index].HashCode;
if hc = EMPTY_HASH then
Break;
bucket := hc and (Length(FItems) - 1);
if not InCircularRange(gap, bucket, index) then
begin
FItems[gap] := FItems[index];
gap := index;
// The gap moved, but we still need to find it to terminate.
FItems[gap].HashCode := EMPTY_HASH;
end;
end;
FItems[gap].HashCode := EMPTY_HASH;
FItems[gap].Key := Default(TKey);
FItems[gap].Value := Default(TValue);
Dec(FCount);
KeyNotify(Key, Notification);
ValueNotify(Result, Notification);
end;
procedure TDictionary<TKey,TValue>.Remove(const Key: TKey);
begin
DoRemove(Key, Hash(Key), cnRemoved);
end;
function TDictionary<TKey,TValue>.ExtractPair(const Key: TKey): TPair<TKey,TValue>;
var
hc, index: Integer;
begin
hc := Hash(Key);
index := GetBucketIndex(Key, hc);
if index < 0 then
Exit(TPair<TKey,TValue>.Create(Key, Default(TValue)));
Result := TPair<TKey,TValue>.Create(Key, DoRemove(Key, hc, cnExtracted));
end;
procedure TDictionary<TKey,TValue>.Clear;
var
i: Integer;
oldItems: TItemArray;
begin
oldItems := FItems;
FCount := 0;
SetLength(FItems, 0);
SetCapacity(0);
FGrowThreshold := 0;
for i := 0 to Length(oldItems) - 1 do
begin
if oldItems[i].HashCode = EMPTY_HASH then
Continue;
KeyNotify(oldItems[i].Key, cnRemoved);
ValueNotify(oldItems[i].Value, cnRemoved);
end;
end;
function TDictionary<TKey, TValue>.ToArray: TArray<TPair<TKey,TValue>>;
begin
Result := ToArrayImpl(Count);
end;
procedure TDictionary<TKey,TValue>.TrimExcess;
begin
// Ensure at least one empty slot for GetBucketIndex to terminate.
SetCapacity(Count + 1);
end;
function TDictionary<TKey,TValue>.TryGetValue(const Key: TKey; out Value: TValue): Boolean;
var
index: Integer;
begin
index := GetBucketIndex(Key, Hash(Key));
Result := index >= 0;
if Result then
Value := FItems[index].Value
else
Value := Default(TValue);
end;
procedure TDictionary<TKey,TValue>.DoAdd(HashCode, Index: Integer; const Key: TKey; const Value: TValue);
begin
FItems[Index].HashCode := HashCode;
FItems[Index].Key := Key;
FItems[Index].Value := Value;
Inc(FCount);
KeyNotify(Key, cnAdded);
ValueNotify(Value, cnAdded);
end;
function TDictionary<TKey, TValue>.DoGetEnumerator: TEnumerator<TPair<TKey, TValue>>;
begin
Result := GetEnumerator;
end;
procedure TDictionary<TKey,TValue>.DoSetValue(Index: Integer; const Value: TValue);
var
oldValue: TValue;
begin
oldValue := FItems[Index].Value;
FItems[Index].Value := Value;
ValueNotify(oldValue, cnRemoved);
ValueNotify(Value, cnAdded);
end;
procedure TDictionary<TKey,TValue>.AddOrSetValue(const Key: TKey; const Value: TValue);
var
hc: Integer;
index: Integer;
begin
hc := Hash(Key);
index := GetBucketIndex(Key, hc);
if index >= 0 then
DoSetValue(index, Value)
else
begin
// We only grow if we are inserting a new value.
if Count >= FGrowThreshold then
begin
Grow;
// We need a new Bucket Index because the array has grown.
index := GetBucketIndex(Key, hc);
end;
DoAdd(hc, not index, Key, Value);
end;
end;
function TDictionary<TKey,TValue>.ContainsKey(const Key: TKey): Boolean;
begin
Result := GetBucketIndex(Key, Hash(Key)) >= 0;
end;
function TDictionary<TKey,TValue>.ContainsValue(const Value: TValue): Boolean;
var
i: Integer;
c: IEqualityComparer<TValue>;
begin
c := TEqualityComparer<TValue>.Default;
for i := 0 to Length(FItems) - 1 do
if (FItems[i].HashCode <> EMPTY_HASH) and c.Equals(FItems[i].Value, Value) then
Exit(True);
Result := False;
end;
function TDictionary<TKey,TValue>.GetEnumerator: TPairEnumerator;
begin
Result := TPairEnumerator.Create(Self);
end;
function TDictionary<TKey,TValue>.GetKeys: TKeyCollection;
begin
if FKeyCollection = nil then
FKeyCollection := TKeyCollection.Create(Self);
Result := FKeyCollection;
end;
function TDictionary<TKey,TValue>.GetValues: TValueCollection;
begin
if FValueCollection = nil then
FValueCollection := TValueCollection.Create(Self);
Result := FValueCollection;
end;
// Pairs
constructor TDictionary<TKey,TValue>.TPairEnumerator.Create(const ADictionary: TDictionary<TKey,TValue>);
begin
inherited Create;
FIndex := -1;
FDictionary := ADictionary;
end;
function TDictionary<TKey, TValue>.TPairEnumerator.DoGetCurrent: TPair<TKey, TValue>;
begin
Result := GetCurrent;
end;
function TDictionary<TKey, TValue>.TPairEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;
function TDictionary<TKey,TValue>.TPairEnumerator.GetCurrent: TPair<TKey,TValue>;
begin
Result.Key := FDictionary.FItems[FIndex].Key;
Result.Value := FDictionary.FItems[FIndex].Value;
end;
function TDictionary<TKey,TValue>.TPairEnumerator.MoveNext: Boolean;
begin
while FIndex < Length(FDictionary.FItems) - 1 do
begin
Inc(FIndex);
if FDictionary.FItems[FIndex].HashCode <> EMPTY_HASH then
Exit(True);
end;
Result := False;
end;
// Keys
constructor TDictionary<TKey,TValue>.TKeyEnumerator.Create(const ADictionary: TDictionary<TKey,TValue>);
begin
inherited Create;
FIndex := -1;
FDictionary := ADictionary;
end;
function TDictionary<TKey, TValue>.TKeyEnumerator.DoGetCurrent: TKey;
begin
Result := GetCurrent;
end;
function TDictionary<TKey, TValue>.TKeyEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;
function TDictionary<TKey,TValue>.TKeyEnumerator.GetCurrent: TKey;
begin
Result := FDictionary.FItems[FIndex].Key;
end;
function TDictionary<TKey,TValue>.TKeyEnumerator.MoveNext: Boolean;
begin
while FIndex < Length(FDictionary.FItems) - 1 do
begin
Inc(FIndex);
if FDictionary.FItems[FIndex].HashCode <> EMPTY_HASH then
Exit(True);
end;
Result := False;
end;
// Values
constructor TDictionary<TKey,TValue>.TValueEnumerator.Create(const ADictionary: TDictionary<TKey,TValue>);
begin
inherited Create;
FIndex := -1;
FDictionary := ADictionary;
end;
function TDictionary<TKey, TValue>.TValueEnumerator.DoGetCurrent: TValue;
begin
Result := GetCurrent;
end;
function TDictionary<TKey, TValue>.TValueEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;
function TDictionary<TKey,TValue>.TValueEnumerator.GetCurrent: TValue;
begin
Result := FDictionary.FItems[FIndex].Value;
end;
function TDictionary<TKey,TValue>.TValueEnumerator.MoveNext: Boolean;
begin
while FIndex < Length(FDictionary.FItems) - 1 do
begin
Inc(FIndex);
if FDictionary.FItems[FIndex].HashCode <> EMPTY_HASH then
Exit(True);
end;
Result := False;
end;
{ TObjectList<T> }
constructor TObjectList<T>.Create(AOwnsObjects: Boolean);
begin
inherited Create;
FOwnsObjects := AOwnsObjects;
end;
constructor TObjectList<T>.Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean);
begin
inherited Create(AComparer);
FOwnsObjects := AOwnsObjects;
end;
constructor TObjectList<T>.Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean);
begin
inherited Create(Collection);
FOwnsObjects := AOwnsObjects;
end;
procedure TObjectList<T>.Notify(const Value: T; Action: TCollectionNotification);
begin
inherited;
if OwnsObjects and (Action = cnRemoved) then
Value.DisposeOf;
end;
{ TObjectQueue<T> }
constructor TObjectQueue<T>.Create(AOwnsObjects: Boolean);
begin
inherited Create;
FOwnsObjects := AOwnsObjects;
end;
constructor TObjectQueue<T>.Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean);
begin
inherited Create(Collection);
FOwnsObjects := AOwnsObjects;
end;
procedure TObjectQueue<T>.Dequeue;
begin
inherited Dequeue;
end;
procedure TObjectQueue<T>.Notify(const Value: T; Action: TCollectionNotification);
begin
inherited;
if OwnsObjects and (Action = cnRemoved) then
Value.DisposeOf;
end;
{ TObjectStack<T> }
constructor TObjectStack<T>.Create(AOwnsObjects: Boolean);
begin
inherited Create;
FOwnsObjects := AOwnsObjects;
end;
constructor TObjectStack<T>.Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean);
begin
inherited Create(Collection);
FOwnsObjects := AOwnsObjects;
end;
procedure TObjectStack<T>.Notify(const Value: T; Action: TCollectionNotification);
begin
inherited;
if OwnsObjects and (Action = cnRemoved) then
Value.DisposeOf;
end;
procedure TObjectStack<T>.Pop;
begin
inherited Pop;
end;
{ TObjectDictionary<TKey,TValue> }
procedure TObjectDictionary<TKey,TValue>.KeyNotify(const Key: TKey; Action: TCollectionNotification);
begin
inherited;
if (Action = cnRemoved) and (doOwnsKeys in FOwnerships) then
PObject(@Key)^.DisposeOf;
end;
procedure TObjectDictionary<TKey,TValue>.ValueNotify(const Value: TValue; Action: TCollectionNotification);
begin
inherited;
if (Action = cnRemoved) and (doOwnsValues in FOwnerships) then
PObject(@Value)^.DisposeOf;
end;
constructor TObjectDictionary<TKey,TValue>.Create(Ownerships: TDictionaryOwnerships;
ACapacity: Integer = 0);
begin
Create(Ownerships, ACapacity, nil);
end;
constructor TObjectDictionary<TKey,TValue>.Create(Ownerships: TDictionaryOwnerships;
const AComparer: IEqualityComparer<TKey>);
begin
Create(Ownerships, 0, AComparer);
end;
constructor TObjectDictionary<TKey,TValue>.Create(Ownerships: TDictionaryOwnerships;
ACapacity: Integer; const AComparer: IEqualityComparer<TKey>);
begin
inherited Create(ACapacity, AComparer);
if doOwnsKeys in Ownerships then
begin
if (TypeInfo(TKey) = nil) or (PTypeInfo(TypeInfo(TKey))^.Kind <> tkClass) then
raise EInvalidCast.CreateRes(@SInvalidCast);
end;
if doOwnsValues in Ownerships then
begin
if (TypeInfo(TValue) = nil) or (PTypeInfo(TypeInfo(TValue))^.Kind <> tkClass) then
raise EInvalidCast.CreateRes(@SInvalidCast);
end;
FOwnerships := Ownerships;
end;
{ TDictionary<TKey, TValue>.TValueCollection }
constructor TDictionary<TKey, TValue>.TValueCollection.Create(const ADictionary: TDictionary<TKey, TValue>);
begin
inherited Create;
FDictionary := ADictionary;
end;
function TDictionary<TKey, TValue>.TValueCollection.DoGetEnumerator: TEnumerator<TValue>;
begin
Result := GetEnumerator;
end;
function TDictionary<TKey, TValue>.TValueCollection.GetCount: Integer;
begin
Result := FDictionary.Count;
end;
function TDictionary<TKey, TValue>.TValueCollection.GetEnumerator: TValueEnumerator;
begin
Result := TValueEnumerator.Create(FDictionary);
end;
function TDictionary<TKey, TValue>.TValueCollection.ToArray: TArray<TValue>;
begin
Result := ToArrayImpl(FDictionary.Count);
end;
{ TDictionary<TKey, TValue>.TKeyCollection }
constructor TDictionary<TKey, TValue>.TKeyCollection.Create(
const ADictionary: TDictionary<TKey, TValue>);
begin
inherited Create;
FDictionary := ADictionary;
end;
function TDictionary<TKey, TValue>.TKeyCollection.DoGetEnumerator: TEnumerator<TKey>;
begin
Result := GetEnumerator;
end;
function TDictionary<TKey, TValue>.TKeyCollection.GetCount: Integer;
begin
Result := FDictionary.Count;
end;
function TDictionary<TKey, TValue>.TKeyCollection.GetEnumerator: TKeyEnumerator;
begin
Result := TKeyEnumerator.Create(FDictionary);
end;
function TDictionary<TKey, TValue>.TKeyCollection.ToArray: TArray<TKey>;
begin
Result := ToArrayImpl(FDictionary.Count);
end;
{ TThreadedQueue<T> }
constructor TThreadedQueue<T>.Create(AQueueDepth: Integer = 10; PushTimeout: LongWord = INFINITE; PopTimeout: LongWord = INFINITE);
begin
inherited Create;
SetLength(FQueue, AQueueDepth);
FQueueLock := TObject.Create;
FQueueNotEmpty := TObject.Create;
FQueueNotFull := TObject.Create;
FPushTimeout := PushTimeout;
FPopTimeout := PopTimeout;
end;
destructor TThreadedQueue<T>.Destroy;
begin
DoShutDown;
FQueueNotFull.Free;
FQueueNotEmpty.Free;
FQueueLock.Free;
inherited;
end;
procedure TThreadedQueue<T>.Grow(ADelta: Integer);
begin
TMonitor.Enter(FQueueLock);
try
SetLength(FQueue, Length(FQueue) + ADelta);
finally
TMonitor.Exit(FQueueLock);
end;
TMonitor.PulseAll(FQueueNotFull);
end;
function TThreadedQueue<T>.PopItem: T;
var
LQueueSize: Integer;
begin
PopItem(LQueueSize, Result);
end;
function TThreadedQueue<T>.PopItem(var AQueueSize: Integer; var AItem: T): TWaitResult;
begin
AItem := Default(T);
TMonitor.Enter(FQueueLock);
try
Result := wrSignaled;
while (Result = wrSignaled) and (FQueueSize = 0) and not FShutDown do
if not TMonitor.Wait(FQueueNotEmpty, FQueueLock, FPopTimeout) then
Result := wrTimeout;
if (FShutDown and (FQueueSize = 0)) or (Result <> wrSignaled) then
Exit;
AItem := FQueue[FQueueOffset];
FQueue[FQueueOffset] := Default(T);
Dec(FQueueSize);
Inc(FQueueOffset);
Inc(FTotalItemsPopped);
if FQueueOffset = Length(FQueue) then
FQueueOffset := 0;
finally
AQueueSize := FQueueSize;
TMonitor.Exit(FQueueLock);
end;
TMonitor.Pulse(FQueueNotFull);
end;
function TThreadedQueue<T>.PopItem(var AItem: T): TWaitResult;
var
LQueueSize: Integer;
begin
Result := PopItem(LQueueSize, AItem);
end;
function TThreadedQueue<T>.PopItem(var AQueueSize: Integer): T;
begin
PopItem(AQueueSize, Result);
end;
function TThreadedQueue<T>.PushItem(const AItem: T): TWaitResult;
var
LQueueSize: Integer;
begin
Result := PushItem(AItem, LQueueSize);
end;
function TThreadedQueue<T>.PushItem(const AItem: T; var AQueueSize: Integer): TWaitResult;
begin
TMonitor.Enter(FQueueLock);
try
Result := wrSignaled;
while (Result = wrSignaled) and (FQueueSize = Length(FQueue)) and not FShutDown do
if not TMonitor.Wait(FQueueNotFull, FQueueLock, FPushTimeout) then
Result := wrTimeout;
if FShutDown or (Result <> wrSignaled) then
Exit;
FQueue[(FQueueOffset + FQueueSize) mod Length(FQueue)] := AItem;
Inc(FQueueSize);
Inc(FTotalItemsPushed);
finally
AQueueSize := FQueueSize;
TMonitor.Exit(FQueueLock);
end;
TMonitor.Pulse(FQueueNotEmpty);
end;
procedure TThreadedQueue<T>.DoShutDown;
begin
TMonitor.Enter(FQueueLock);
try
FShutDown := True;
finally
TMonitor.Exit(FQueueLock);
end;
TMonitor.PulseAll(FQueueNotFull);
TMonitor.PulseAll(FQueueNotEmpty);
end;
{ TThreadList<T> }
procedure TThreadList<T>.Add(const Item: T);
begin
LockList;
try
if (Duplicates = dupAccept) or
(FList.IndexOf(Item) = -1) then
FList.Add(Item)
else if Duplicates = dupError then
raise EListError.CreateFmt(SDuplicateItem, [FList.ItemValue(Item)]);
finally
UnlockList;
end;
end;
procedure TThreadList<T>.Clear;
begin
LockList;
try
FList.Clear;
finally
UnlockList;
end;
end;
constructor TThreadList<T>.Create;
begin
inherited Create;
FLock := TObject.Create;
FList := TList<T>.Create;
FDuplicates := dupIgnore;
end;
destructor TThreadList<T>.Destroy;
begin
LockList; // Make sure nobody else is inside the list.
try
FList.Free;
inherited Destroy;
finally
UnlockList;
FLock.Free;
end;
end;
function TThreadList<T>.LockList: TList<T>;
begin
TMonitor.Enter(FLock);
Result := FList;
end;
procedure TThreadList<T>.Remove(const Item: T);
begin
RemoveItem(Item, TDirection.FromBeginning);
end;
procedure TThreadList<T>.RemoveItem(const Item: T; Direction: TDirection);
begin
LockList;
try
FList.RemoveItem(Item, Direction);
finally
UnlockList;
end;
end;
procedure TThreadList<T>.UnlockList;
begin
TMonitor.Exit(FLock);
end;
{ TArrayMoveManager<T> }
procedure TMoveArrayManager<T>.Finalize(var AArray: array of T; Index, Count: Integer);
begin
System.FillChar(AArray[Index], Count * SizeOf(T), 0);
end;
procedure TMoveArrayManager<T>.Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer);
begin
System.Move(AArray[FromIndex], AArray[ToIndex], Count * SizeOf(T));
end;
procedure TMoveArrayManager<T>.Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer);
begin
System.Move(FromArray[FromIndex], ToArray[ToIndex], Count * SizeOf(T));
end;
{$IF Defined(WEAKREF)}
procedure TManualArrayManager<T>.Finalize(var AArray: array of T; Index, Count: Integer);
begin
System.Finalize(AArray[Index], Count);
System.FillChar(AArray[Index], Count * SizeOf(T), 0);
end;
procedure TManualArrayManager<T>.Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer);
var
I: Integer;
begin
if Count > 0 then
if FromIndex < ToIndex then
for I := Count - 1 downto 0 do
AArray[ToIndex + I] := AArray[FromIndex + I]
else if FromIndex > ToIndex then
for I := 0 to Count - 1 do
AArray[ToIndex + I] := AArray[FromIndex + I];
end;
procedure TManualArrayManager<T>.Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer);
var
I: Integer;
begin
if Count > 0 then
if FromIndex < ToIndex then
for I := Count - 1 downto 0 do
ToArray[ToIndex + I] := FromArray[FromIndex + I]
else if FromIndex > ToIndex then
for I := 0 to Count - 1 do
ToArray[ToIndex + I] := FromArray[FromIndex + I];
end;
{$ENDIF}
end.
-
험프리
2017.09.29 09:10
우선 의심이 가는 부분이
제너릭으로 선언된 데이터타입과 생성한 데이터 타입이 다르네요.
선언
FTimeRanges: TList<TTimeRange>;
생성
FTimeRanges := TObjectList<TTimeRange>.Create;
특별한 이유가 있어서 이렇게 구현하셨을 것 같은데요. 영향이 있지 않을까요?
위 데이터타입을 일치해 보시기 바랍니다.
-
delphi
2017.09.29 10:21
혹 말씀한거 말고 수정해야 할 부분이 있을까요?
이소스 그대로 32-bit 윈도우에서는 정상 작동 합니다.
procedure TTimeCalculator.Init(ATimeRange: TTimeRange);
begin
FTimeRanges.Clear; <===========디버깅 해보니 이부분에서 오류 .apk raised exception class segmentation fault (11). 발생
FTimeRanges.Add(ATimeRange);
end;
Firemonkey 델파이 XE7에서 안드로이드로 실행시.apk raised exception class segmentation fault (11). 오류 (미해결중입니다)
2017.09.28 10:20
안녕하세요
델파이 XE7 System.Generics.Collections 사용시 32-bit 윈도우에서는 정상적으로 사용 가능합니다.
그런데 안드로이드 모바일에서 사용하면 오류가 납니다.
혹 안드로이드용, 윈도우용 System.Generics.Collections 화일이 따로 있는건가요?
오류메새지 : .apk raised exception class segmentation fault (11).
현재 제가 사용하고 있는 System.Generics.Collections 일부입니다
{*******************************************************}
{ }
{ CodeGear Delphi Runtime Library }
{ }
{ Copyright(c) 1995-2014 Embarcadero Technologies, Inc. }
{ }
{*******************************************************}
unit System.Generics.Collections;
{$R-,T-,X+,H+,B-}
interface
uses
System.Types, System.SysUtils, System.Generics.Defaults;
.
.
.
{ TList<T> }
function TList<T>.GetCapacity: Integer;
begin
Result := Length(FItems); <===== 이부분에 .apk raised exception class segmentation fault (11). 오류발생
end;
댓글 6
-
험프리
2017.09.28 14:56
-
delphi
2017.09.28 23:50
도움주셔서 감사합니다.
제가 사용 한 소스와 TimeCalculator 호출 소스, System.Generics.Collections; 입니다
중간마다 1),2),3) 으로 제가 디버깅 한 순서를 표시 해두었습니다
검토 부탁드립니다
=============== 작성한 소스 ===============
procedure TAttendanceInputView.CalcTime_Ver2;
var
StartTime: TDateTime;
EndTime: TDateTime;
ExtraStartTime: Extended;
ExtraEndTime: Extended;
begin
FDefaultTime := 0;
FOverTime := 0;
FNightTime := 0;
FHolidayTime := 0;
FHolidayOverTime := 0;
if (TimeOf(dtpStartTime.Time) = EncodeTime(0, 0, 0, 0))
and (TimeOf(dtpEndTime.Time) = EncodeTime(0, 0, 0, 0)) then
begin
Exit;
end;
if TimeOf(dtpStartTime.Time) < TimeOf(dtpEndTime.Time) then
begin
StartTime := DateOf(DateTimePicker.Date) + TimeOf(dtpStartTime.Time);
EndTime := DateOf(DateTimePicker.Date) + TimeOf(dtpEndTime.Time);
end
else
begin
StartTime := DateOf(DateTimePicker.Date) + TimeOf(dtpStartTime.Time);
EndTime := IncDay(DateOf(DateTimePicker.Date)) + TimeOf(dtpEndTime.Time);
end;
ExtraStartTime := 0;
ExtraEndTime := 0;
if not VarIsNull(cmbAttendanceCategory.EditValue) then
begin
if LookupModule.qry_ATTENDANCE_EXTRA_CATEGORY_IS_WORK.Value = 'N' then
begin
if TimeOf(dtpExtraStartTime.Time) < TimeOf(dtpExtraEndTime.Time) then
begin
ExtraStartTime := DateOf(DateTimePicker.Date) + TimeOf(dtpExtraStartTime.Time);
ExtraEndTime := DateOf(DateTimePicker.Date) + TimeOf(dtpExtraEndTime.Time);
end
else
begin
ExtraStartTime := DateOf(DateTimePicker.Date) + TimeOf(dtpExtraStartTime.Time);
ExtraEndTime := IncDay(DateOf(DateTimePicker.Date)) + TimeOf(dtpExtraEndTime.Time);
end;
end;
end;
FTimeCalculator.Init(StartTime, EndTime); <=== 1) 이문장 부터 호출 시작 입니다
DateOf(DateTimePicker.Date) + EncodeTime(12, 30, 0, 0),
DateOf(DateTimePicker.Date) + EncodeTime(13, 30, 0, 0)
);
FTimeCalculator.Exclude(
DateOf(DateTimePicker.Date) + EncodeTime(17, 30, 0, 0),
DateOf(DateTimePicker.Date) + EncodeTime(18, 30, 0, 0)
);
if (ExtraStartTime > 0) and (ExtraEndTime > 0) then
FTimeCalculator.Exclude(ExtraStartTime, ExtraEndTime);
FNightTime := FTimeCalculator.ToMinutesAndFree(FTimeCalculator.Intersects(
DateOf(DateTimePicker.Date) + EncodeTime(22, 0, 0, 0),
IncDay(DateOf(DateTimePicker.Date)) + EncodeTime(6, 0, 0, 0)
));
FTimeCalculator.Exclude(
DateOf(IncDay(DateTimePicker.Date)) + EncodeTime(0, 30, 0, 0),
DateOf(IncDay(DateTimePicker.Date)) + EncodeTime(1, 30, 0, 0)
);
FTimeCalculator.Exclude(
DateOf(IncDay(DateTimePicker.Date)) + EncodeTime(6, 30, 0, 0),
DateOf(IncDay(DateTimePicker.Date)) + EncodeTime(7, 30, 0, 0)
);
FDefaultTime := FTimeCalculator.ToMinutes(FTimeCalculator.TimeRanges);
if FDefaultTime > 8 * 60 then
begin
FOverTime := FDefaultTime - (8 * 60);
FDefaultTime := 8 * 60;
end;
if DayOfTheWeek(DateTimePicker.Date) in [DaySaturday, DaySunday] then
begin
FHolidayTime := FDefaultTime;
FHolidayOverTime := FOverTime;
FDefaultTime := 0;
FOverTime := 0;
end;
edDefaultTime.Text := Format('%.2d:%.2d', [FDefaultTime div 60, FDefaultTime mod 60]);
edOverTime.Text := Format('%.2d:%.2d', [FOverTime div 60, FOverTime mod 60]);
edHolidayTime.Text := Format('%.2d:%.2d', [FHolidayTime div 60, FHolidayTime mod 60]);
edHolidayOverTime.Text := Format('%.2d:%.2d', [FHolidayOverTime div 60, FHolidayOverTime mod 60]);
edNightTime.Text := Format('%.2d:%.2d', [FNightTime div 60, FNightTime mod 60]);
end;
-
delphi
2017.09.29 08:37
================== 호출한 소스 TimeCalculator 호출 (FTimeCalculator) ===========================
unit TimeCalculator;
interface
uses
System.DateUtils,
System.Generics.Collections;
type
TTimeRange = class
public
From: TDateTime;
&To: TDateTime;
constructor Create(AFrom: TDateTime; ATo: TDateTime);
function IsEmpty: Boolean;
end;
TTimeCalculator = class
private
FTimeRanges: TList<TTimeRange>;
function GetCount: Integer;
function GetRange(Index: Integer): TTimeRange;
public
constructor Create;
destructor Destroy; override;
procedure Init(AFrom: TDateTime; ATo: TDateTime); overload;
procedure Init(ATimeRange: TTimeRange); overload;
procedure Exclude(AFrom: TDateTime; ATo: TDateTime); overload;
procedure Exclude(ATimeRange: TTimeRange); overload;
function Intersects(AFrom: TDateTime; ATo: TDateTime): TList<TTimeRange>; overload;
function Intersects(ATimeRange: TTimeRange): TList<TTimeRange>; overload;
property Ranges[Index: Integer]: TTimeRange read GetRange;
property RangeCount: Integer read GetCount;
property TimeRanges: TList<TTimeRange> read FTimeRanges;
class function ToMinutes(TimeRanges: TList<TTimeRange>): Integer;
class function ToHours(TimeRanges: TList<TTimeRange>): Integer;
class function ToMinutesAndFree(TimeRanges: TList<TTimeRange>): Integer;
class function ToHoursAndFree(TimeRanges: TList<TTimeRange>): Integer;
class function Intersect(Left: TTimeRange; Right: TTimeRange): TTimeRange;
end;
implementation
{ TTimeCalculator }
constructor TTimeCalculator.Create;
begin
FTimeRanges := TObjectList<TTimeRange>.Create;
end;
destructor TTimeCalculator.Destroy;
begin
FTimeRanges.Free;
inherited;
end;
procedure TTimeCalculator.Exclude(ATimeRange: TTimeRange);
var
I: Integer;
TimeRange: TTimeRange;
begin
for I := FTimeRanges.Count - 1 downto 0 do
begin
TimeRange := Intersect(FTimeRanges.Items[I], ATimeRange);
try
if not TimeRange.IsEmpty then
begin
if (FTimeRanges.Items[I].&From < TimeRange.From)
and (TimeRange.&To < FTimeRanges.Items[I].&To) then
begin
FTimeRanges.Add(TTimeRange.Create(TimeRange.&To, FTimeRanges.Items[I].&To));
FTimeRanges.Items[I].&To := TimeRange.From;
end
else if (FTimeRanges.Items[I].&From < TimeRange.From)
and (TimeRange.&To = FTimeRanges.Items[I].&To) then
begin
FTimeRanges.Items[I].&To := TimeRange.From;
end
else if (FTimeRanges.Items[I].&From = TimeRange.From)
and (TimeRange.&To < FTimeRanges.Items[I].&To) then
begin
FTimeRanges.Items[I].From := TimeRange.&To;
end
else
begin
FTimeRanges.Delete(I);
end;
end;
finally
TimeRange.Free;
end;
end;
end;
procedure TTimeCalculator.Exclude(AFrom, ATo: TDateTime);
begin
Exclude(TTimeRange.Create(AFrom, ATo));
end;
function TTimeCalculator.GetCount: Integer;
begin
Result := FTimeRanges.Count;
end;
function TTimeCalculator.GetRange(Index: Integer): TTimeRange;
begin
Result := FTimeRanges.Items[Index];
end;
procedure TTimeCalculator.Init(AFrom, ATo: TDateTime);
begin
Init(TTimeRange.Create(AFrom, ATo)); //2) 여기서 호출시 오류 나는거 같습니다
end;
procedure TTimeCalculator.Init(ATimeRange: TTimeRange);
begin
FTimeRanges.Clear;
FTimeRanges.Add(ATimeRange);
end;
function TTimeCalculator.Intersects(AFrom, ATo: TDateTime): TList<TTimeRange>;
begin
Result := Intersects(TTimeRange.Create(AFrom, ATo));
end;
class function TTimeCalculator.Intersect(Left, Right: TTimeRange): TTimeRange;
begin
if (Left.&To > Right.From) and (Left.From < Right.&To) then
begin
Result := TTimeRange.Create(0, 0);
if Left.From < Right.From then
Result.From := Right.From
else
Result.From := Left.From;
if Left.&To < Right.&To then
Result.&To := Left.&To
else
Result.&To := Right.&To;
end
else
begin
Result := TTimeRange.Create(0, 0);
end;
end;
function TTimeCalculator.Intersects(ATimeRange: TTimeRange): TList<TTimeRange>;
var
I: Integer;
TimeRange: TTimeRange;
begin
Result := TObjectList<TTimeRange>.Create;
for I := 0 to FTimeRanges.Count - 1 do
begin
TimeRange := Intersect(FTimeRanges.Items[I], ATimeRange);
if TimeRange.IsEmpty then
TimeRange.Free
else
Result.Add(TimeRange);
end;
end;
class function TTimeCalculator.ToHours(TimeRanges: TList<TTimeRange>): Integer;
begin
Result := ToMinutes(TimeRanges) div 60;
end;
class function TTimeCalculator.ToHoursAndFree(
TimeRanges: TList<TTimeRange>): Integer;
begin
try
Result := ToHours(TimeRanges);
finally
TimeRanges.Free;
end;
end;
class function TTimeCalculator.ToMinutes(
TimeRanges: TList<TTimeRange>): Integer;
var
I: Integer;
begin
Result := 0;
for I := 0 to TimeRanges.Count - 1 do
Result := Result + MinutesBetween(TimeRanges.Items[I].From, TimeRanges.Items[I].&To);
end;
class function TTimeCalculator.ToMinutesAndFree(
TimeRanges: TList<TTimeRange>): Integer;
begin
try
Result := ToMinutes(TimeRanges);
finally
TimeRanges.Free;
end;
end;
{ TTimeRange }
constructor TTimeRange.Create(AFrom, ATo: TDateTime);
begin
From := AFrom;
&To := ATo;
end;
function TTimeRange.IsEmpty: Boolean;
begin
Result := From = &To;
end;
end.
======================================================================
-
delphi
2017.09.29 08:37
========================== System.Generics.Collections;===============================
{*******************************************************}
{ }
{ CodeGear Delphi Runtime Library }
{ }
{ Copyright(c) 1995-2014 Embarcadero Technologies, Inc. }
{ }
{*******************************************************}unit System.Generics.Collections;
{$R-,T-,X+,H+,B-}
interface
uses
System.Types, System.SysUtils, System.Generics.Defaults;type
TArray = class
private
class procedure QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>;
L, R: Integer); static;
class procedure CheckArrays(Source, Destination: Pointer; SourceIndex, SourceLength, DestIndex, DestLength, Count: NativeInt); static;
public
class procedure Sort<T>(var Values: array of T); overload; static;
class procedure Sort<T>(var Values: array of T; const Comparer: IComparer<T>); overload; static;
class procedure Sort<T>(var Values: array of T;
const Comparer: IComparer<T>; Index, Count: Integer); overload; static;class function BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>;
Index, Count: Integer): Boolean; overload; static;
class function BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>): Boolean; overload; static;
class function BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer): Boolean; overload; static; static;class procedure Copy<T>(const Source, Destination: array of T; SourceIndex, DestIndex, Count: NativeInt); overload; static;
class procedure Copy<T>(const Source, Destination: array of T; Count: NativeInt); overload; static;
end;
TCollectionNotification = (cnAdded, cnRemoved, cnExtracted);
TCollectionNotifyEvent<T> = procedure(Sender: TObject; const Item: T;
Action: TCollectionNotification) of object;TEnumerator<T> = class abstract
protected
function DoGetCurrent: T; virtual; abstract;
function DoMoveNext: Boolean; virtual; abstract;
public
property Current: T read DoGetCurrent;
function MoveNext: Boolean;
end;TEnumerable<T> = class abstract
private
{$HINTS OFF}
function ToArrayImpl(Count: Integer): TArray<T>; // used by descendants
{$HINTS ON}
protected
function DoGetEnumerator: TEnumerator<T>; virtual; abstract;
public
destructor Destroy; override;
function GetEnumerator: TEnumerator<T>;
function ToArray: TArray<T>; virtual;
end;TArrayManager<T> = class abstract
public
procedure Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer); overload; virtual; abstract;
procedure Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer); overload; virtual; abstract;
procedure Finalize(var AArray: array of T; Index, Count: Integer); virtual; abstract;
end;TMoveArrayManager<T> = class(TArrayManager<T>)
public
procedure Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer); overload; override;
procedure Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer); overload; override;
procedure Finalize(var AArray: array of T; Index, Count: Integer); override;
end;{$IF Defined(WEAKREF)}
TManualArrayManager<T> = class(TArrayManager<T>)
public
procedure Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer); overload; override;
procedure Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer); overload; override;
procedure Finalize(var AArray: array of T; Index, Count: Integer); override;
end;
{$ENDIF}TList<T> = class(TEnumerable<T>)
private
type
arrayofT = array of T;
var
FItems: arrayofT;
FCount: Integer;
FComparer: IComparer<T>;
FOnNotify: TCollectionNotifyEvent<T>;
FArrayManager: TArrayManager<T>;function GetCapacity: Integer;
procedure SetCapacity(Value: Integer);
procedure SetCount(Value: Integer);
function GetItem(Index: Integer): T;
procedure SetItem(Index: Integer; const Value: T);
procedure Grow(ACount: Integer);
procedure GrowCheck(ACount: Integer); inline;
procedure DoDelete(Index: Integer; Notification: TCollectionNotification);
protected
function ItemValue(const Item: T): NativeInt;
function DoGetEnumerator: TEnumerator<T>; override;
procedure Notify(const Item: T; Action: TCollectionNotification); virtual;
public
type
TDirection = System.Types.TDirection;
TEmptyFunc = reference to function (const L, R: T): Boolean;
TListCompareFunc = reference to function (const L, R: T): Integer;constructor Create; overload;
constructor Create(const AComparer: IComparer<T>); overload;
constructor Create(const Collection: TEnumerable<T>); overload;
destructor Destroy; override;class procedure Error(const Msg: string; Data: NativeInt); overload; virtual;
{$IFNDEF NEXTGEN}
class procedure Error(Msg: PResStringRec; Data: NativeInt); overload;
{$ENDIF NEXTGEN}function Add(const Value: T): Integer;
procedure AddRange(const Values: array of T); overload;
procedure AddRange(const Collection: IEnumerable<T>); overload;
procedure AddRange(const Collection: TEnumerable<T>); overload;procedure Insert(Index: Integer; const Value: T);
procedure InsertRange(Index: Integer; const Values: array of T); overload;
procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;procedure Pack; overload;
procedure Pack(const IsEmpty: TEmptyFunc); overload;function Remove(const Value: T): Integer;
function RemoveItem(const Value: T; Direction: TDirection): Integer;
procedure Delete(Index: Integer);
procedure DeleteRange(AIndex, ACount: Integer);
function Extract(const Value: T): T;
function ExtractItem(const Value: T; Direction: TDirection): T;procedure Exchange(Index1, Index2: Integer);
procedure Move(CurIndex, NewIndex: Integer);function First: T;
function Last: T;procedure Clear;
function Expand: TList<T>;
function Contains(const Value: T): Boolean;
function IndexOf(const Value: T): Integer;
function IndexOfItem(const Value: T; Direction: TDirection): Integer;
function LastIndexOf(const Value: T): Integer;
procedure Reverse;
procedure Sort; overload;
procedure Sort(const AComparer: IComparer<T>); overload;
function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;
function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;
procedure TrimExcess;function ToArray: TArray<T>; override; final;
property Capacity: Integer read GetCapacity write SetCapacity;
property Count: Integer read FCount write SetCount;
property Items[Index: Integer]: T read GetItem write SetItem; default;
property List: arrayofT read FItems;property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
type
TEnumerator = class(TEnumerator<T>)
private
FList: TList<T>;
FIndex: Integer;
function GetCurrent: T;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const AList: TList<T>);
property Current: T read GetCurrent;
function MoveNext: Boolean;
end;
function GetEnumerator: TEnumerator; reintroduce;
end;TThreadList<T> = class
private
FList: TList<T>;
FLock: TObject;
FDuplicates: TDuplicates;
public
constructor Create;
destructor Destroy; override;
procedure Add(const Item: T);
procedure Clear;
function LockList: TList<T>;
procedure Remove(const Item: T); inline;
procedure RemoveItem(const Item: T; Direction: TDirection);
procedure UnlockList; inline;
property Duplicates: TDuplicates read FDuplicates write FDuplicates;
end;
// Queue implemented over array, using wrapping.
TQueue<T> = class(TEnumerable<T>)
private
FHead: Integer;
FTail: Integer;
FCount: Integer;
FItems: array of T;
FOnNotify: TCollectionNotifyEvent<T>;
FArrayManager: TArrayManager<T>;
procedure Grow;
procedure SetCapacity(Value: Integer);
function DoDequeue(Notification: TCollectionNotification): T;
procedure DoSetCapacity(Value: Integer);
function GetCapacity: Integer;
protected
function DoGetEnumerator: TEnumerator<T>; override;
procedure Notify(const Item: T; Action: TCollectionNotification); virtual;
public
constructor Create; overload;
constructor Create(const Collection: TEnumerable<T>); overload;
destructor Destroy; override;
procedure Enqueue(const Value: T);
function Dequeue: T;
function Extract: T;
function Peek: T;
procedure Clear;
procedure TrimExcess;
property Count: Integer read FCount;
property Capacity: Integer read GetCapacity write DoSetCapacity;
property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
function ToArray: TArray<T>; override; final;
type
TEnumerator = class(TEnumerator<T>)
private
FQueue: TQueue<T>;
FIndex: Integer;
function GetCurrent: T;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const AQueue: TQueue<T>);
property Current: T read GetCurrent;
function MoveNext: Boolean;
end;
function GetEnumerator: TEnumerator; reintroduce;
end;
TStack<T> = class(TEnumerable<T>)
private
FCount: Integer;
FItems: array of T;
FOnNotify: TCollectionNotifyEvent<T>;
procedure Grow;
function DoPop(Notification: TCollectionNotification): T;
procedure DoSetCapacity(Value: Integer);
function GetCapacity: Integer;
protected
function DoGetEnumerator: TEnumerator<T>; override;
procedure Notify(const Item: T; Action: TCollectionNotification); virtual;
public
constructor Create(const Collection: TEnumerable<T>); overload;
destructor Destroy; override;
procedure Clear;
procedure Push(const Value: T);
function Pop: T;
function Peek: T;
function Extract: T;
procedure TrimExcess;
function ToArray: TArray<T>; override; final;
property Count: Integer read FCount;
property Capacity: Integer read GetCapacity write DoSetCapacity;
property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
type
TEnumerator = class(TEnumerator<T>)
private
FStack: TStack<T>;
FIndex: Integer;
function GetCurrent: T;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const AStack: TStack<T>);
property Current: T read GetCurrent;
function MoveNext: Boolean;
end;function GetEnumerator: TEnumerator; reintroduce;
end;TPair<TKey,TValue> = record
Key: TKey;
Value: TValue;
constructor Create(const AKey: TKey; const AValue: TValue);
end;// Hash table using linear probing
TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)
private
type
TItem = record
HashCode: Integer;
Key: TKey;
Value: TValue;
end;
TItemArray = array of TItem;
private
FItems: TItemArray;
FCount: Integer;
FComparer: IEqualityComparer<TKey>;
FGrowThreshold: Integer;
procedure SetCapacity(ACapacity: Integer);
procedure Rehash(NewCapPow2: Integer);
procedure Grow;
function GetBucketIndex(const Key: TKey; HashCode: Integer): Integer;
function Hash(const Key: TKey): Integer;
function GetItem(const Key: TKey): TValue;
procedure SetItem(const Key: TKey; const Value: TValue);
procedure RehashAdd(HashCode: Integer; const Key: TKey; const Value: TValue);
procedure DoAdd(HashCode, Index: Integer; const Key: TKey; const Value: TValue);
procedure DoSetValue(Index: Integer; const Value: TValue);
function DoRemove(const Key: TKey; HashCode: Integer; Notification: TCollectionNotification): TValue;
protected
function DoGetEnumerator: TEnumerator<TPair<TKey,TValue>>; override;
procedure KeyNotify(const Key: TKey; Action: TCollectionNotification); virtual;
procedure ValueNotify(const Value: TValue; Action: TCollectionNotification); virtual;
public
constructor Create(ACapacity: Integer = 0); overload;
constructor Create(const AComparer: IEqualityComparer<TKey>); overload;
constructor Create(ACapacity: Integer; const AComparer: IEqualityComparer<TKey>); overload;
constructor Create(const Collection: TEnumerable<TPair<TKey,TValue>>); overload;
constructor Create(const Collection: TEnumerable<TPair<TKey,TValue>>; const AComparer: IEqualityComparer<TKey>); overload;
destructor Destroy; override;
procedure Add(const Key: TKey; const Value: TValue);
procedure Remove(const Key: TKey);
function ExtractPair(const Key: TKey): TPair<TKey,TValue>;
procedure Clear;
procedure TrimExcess;
function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
procedure AddOrSetValue(const Key: TKey; const Value: TValue);
function ContainsKey(const Key: TKey): Boolean;
function ContainsValue(const Value: TValue): Boolean;
function ToArray: TArray<TPair<TKey,TValue>>; override; final;
property Items[const Key: TKey]: TValue read GetItem write SetItem; default;
property Count: Integer read FCount;
type
TPairEnumerator = class(TEnumerator<TPair<TKey,TValue>>)
private
FDictionary: TDictionary<TKey,TValue>;
FIndex: Integer;
function GetCurrent: TPair<TKey,TValue>;
protected
function DoGetCurrent: TPair<TKey,TValue>; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
property Current: TPair<TKey,TValue> read GetCurrent;
function MoveNext: Boolean;
end;TKeyEnumerator = class(TEnumerator<TKey>)
private
FDictionary: TDictionary<TKey,TValue>;
FIndex: Integer;
function GetCurrent: TKey;
protected
function DoGetCurrent: TKey; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
property Current: TKey read GetCurrent;
function MoveNext: Boolean;
end;TValueEnumerator = class(TEnumerator<TValue>)
private
FDictionary: TDictionary<TKey,TValue>;
FIndex: Integer;
function GetCurrent: TValue;
protected
function DoGetCurrent: TValue; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
property Current: TValue read GetCurrent;
function MoveNext: Boolean;
end;TValueCollection = class(TEnumerable<TValue>)
private
[Weak] FDictionary: TDictionary<TKey,TValue>;
function GetCount: Integer;
protected
function DoGetEnumerator: TEnumerator<TValue>; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
function GetEnumerator: TValueEnumerator; reintroduce;
function ToArray: TArray<TValue>; override; final;
property Count: Integer read GetCount;
end;TKeyCollection = class(TEnumerable<TKey>)
private
[Weak] FDictionary: TDictionary<TKey,TValue>;
function GetCount: Integer;
protected
function DoGetEnumerator: TEnumerator<TKey>; override;
public
constructor Create(const ADictionary: TDictionary<TKey,TValue>);
function GetEnumerator: TKeyEnumerator; reintroduce;
function ToArray: TArray<TKey>; override; final;
property Count: Integer read GetCount;
end;
private
FOnKeyNotify: TCollectionNotifyEvent<TKey>;
FOnValueNotify: TCollectionNotifyEvent<TValue>;
FKeyCollection: TKeyCollection;
FValueCollection: TValueCollection;
function GetKeys: TKeyCollection;
function GetValues: TValueCollection;
public
function GetEnumerator: TPairEnumerator; reintroduce;
property Keys: TKeyCollection read GetKeys;
property Values: TValueCollection read GetValues;
property OnKeyNotify: TCollectionNotifyEvent<TKey> read FOnKeyNotify write FOnKeyNotify;
property OnValueNotify: TCollectionNotifyEvent<TValue> read FOnValueNotify write FOnValueNotify;
end;
TObjectList<T: class> = class(TList<T>)
private
FOwnsObjects: Boolean;
protected
procedure Notify(const Value: T; Action: TCollectionNotification); override;
public
constructor Create(AOwnsObjects: Boolean = True); overload;
constructor Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean = True); overload;
constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
end;TObjectQueue<T: class> = class(TQueue<T>)
private
FOwnsObjects: Boolean;
protected
procedure Notify(const Value: T; Action: TCollectionNotification); override;
public
constructor Create(AOwnsObjects: Boolean = True); overload;
constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
procedure Dequeue;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
end;TObjectStack<T: class> = class(TStack<T>)
private
FOwnsObjects: Boolean;
protected
procedure Notify(const Value: T; Action: TCollectionNotification); override;
public
constructor Create(AOwnsObjects: Boolean = True); overload;
constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
procedure Pop;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
end;TDictionaryOwnerships = set of (doOwnsKeys, doOwnsValues);
TObjectDictionary<TKey,TValue> = class(TDictionary<TKey,TValue>)
private
FOwnerships: TDictionaryOwnerships;
protected
procedure KeyNotify(const Key: TKey; Action: TCollectionNotification); override;
procedure ValueNotify(const Value: TValue; Action: TCollectionNotification); override;
public
constructor Create(Ownerships: TDictionaryOwnerships; ACapacity: Integer = 0); overload;
constructor Create(Ownerships: TDictionaryOwnerships;
const AComparer: IEqualityComparer<TKey>); overload;
constructor Create(Ownerships: TDictionaryOwnerships; ACapacity: Integer;
const AComparer: IEqualityComparer<TKey>); overload;
end;
TThreadedQueue<T> = class
private
FQueue: array of T;
FQueueSize, FQueueOffset: Integer;
FQueueNotEmpty,
FQueueNotFull: TObject;
FQueueLock: TObject;
FShutDown: Boolean;
FPushTimeout, FPopTimeout: LongWord;
FTotalItemsPushed, FTotalItemsPopped: LongWord;
public
constructor Create(AQueueDepth: Integer = 10; PushTimeout: LongWord = INFINITE; PopTimeout: LongWord = INFINITE);
destructor Destroy; override;procedure Grow(ADelta: Integer);
function PushItem(const AItem: T): TWaitResult; overload;
function PushItem(const AItem: T; var AQueueSize: Integer): TWaitResult; overload;
function PopItem: T; overload;
function PopItem(var AQueueSize: Integer): T; overload;
function PopItem(var AQueueSize: Integer; var AItem: T): TWaitResult; overload;
function PopItem(var AItem: T): TWaitResult; overload;
procedure DoShutDown;property QueueSize: Integer read FQueueSize;
property ShutDown: Boolean read FShutDown;
property TotalItemsPushed: LongWord read FTotalItemsPushed;
property TotalItemsPopped: LongWord read FTotalItemsPopped;
end;PObject = ^TObject;
function InCircularRange(Bottom, Item, TopInc: Integer): Boolean; inline;
implementation
uses System.TypInfo, System.SysConst, System.RTLConsts;
{ TArray }
class function TArray.BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>; Index,
Count: Integer): Boolean;
var
L, H: Integer;
mid, cmp: Integer;
begin
if (Index < Low(Values)) or ((Index > High(Values)) and (Count > 0))
or (Index + Count - 1 > High(Values)) or (Count < 0)
or (Index + Count < 0) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if Count = 0 then
begin
FoundIndex := Index;
Exit(False);
end;
Result := False;
L := Index;
H := Index + Count - 1;
while L <= H do
begin
mid := L + (H - L) shr 1;
cmp := Comparer.Compare(Values[mid], Item);
if cmp < 0 then
L := mid + 1
else
begin
H := mid - 1;
if cmp = 0 then
Result := True;
end;
end;
FoundIndex := L;
end;class function TArray.BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>): Boolean;
begin
Result := BinarySearch<T>(Values, Item, FoundIndex, Comparer,
Low(Values), Length(Values));
end;class function TArray.BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer): Boolean;
begin
Result := BinarySearch<T>(Values, Item, FoundIndex, TComparer<T>.Default,
Low(Values), Length(Values));
end;class procedure TArray.Copy<T>(const Source, Destination: array of T; SourceIndex, DestIndex, Count: NativeInt);
begin
CheckArrays(PPointer(@Source)^, PPointer(@Destination)^, SourceIndex, Length(Source), DestIndex, Length(Destination), Count);
System.CopyArray(Pointer(@Destination[SourceIndex]), Pointer(@Source[SourceIndex]), TypeInfo(T), Count);
end;class procedure TArray.CheckArrays(Source, Destination: Pointer; SourceIndex, SourceLength, DestIndex, DestLength, Count: NativeInt);
begin
if (SourceIndex < 0) or (DestIndex < 0) or (SourceIndex >= SourceLength) or (DestIndex >= DestLength) or
(SourceIndex + Count >= SourceLength) or (DestIndex + Count >= DestLength) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if Source = Destination then
raise EArgumentException.CreateRes(@sSameArrays);
end;class procedure TArray.Copy<T>(const Source, Destination: array of T; Count: NativeInt);
begin
Copy(Source, Destination, 0, 0, Count);
end;class procedure TArray.QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>;
L, R: Integer);
var
I, J: Integer;
pivot, temp: T;
begin
if (Length(Values) = 0) or ((R - L) <= 0) then
Exit;
repeat
I := L;
J := R;
pivot := Values[L + (R - L) shr 1];
repeat
while Comparer.Compare(Values[I], pivot) < 0 do
Inc(I);
while Comparer.Compare(Values[J], pivot) > 0 do
Dec(J);
if I <= J then
begin
if I <> J then
begin
temp := Values[I];
Values[I] := Values[J];
Values[J] := temp;
end;
Inc(I);
Dec(J);
end;
until I > J;
if L < J then
QuickSort<T>(Values, Comparer, L, J);
L := I;
until I >= R;
end;class procedure TArray.Sort<T>(var Values: array of T);
begin
QuickSort<T>(Values, TComparer<T>.Default, Low(Values), High(Values));
end;class procedure TArray.Sort<T>(var Values: array of T; const Comparer: IComparer<T>);
begin
QuickSort<T>(Values, Comparer, Low(Values), High(Values));
end;class procedure TArray.Sort<T>(var Values: array of T; const Comparer: IComparer<T>;
Index, Count: Integer);
begin
if (Index < Low(Values)) or ((Index > High(Values)) and (Count > 0))
or (Index + Count - 1 > High(Values)) or (Count < 0)
or (Index + Count < 0) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if Count <= 1 then
Exit;
QuickSort<T>(Values, Comparer, Index, Index + Count - 1);
end;{ TEnumerator<T> }
function TEnumerator<T>.MoveNext: Boolean;
begin
Result := DoMoveNext;
end;{ TEnumerable<T> }
// The overridden destructor that simply invokes 'inherited' is
// required to instantiate the destructor for C++ code
destructor TEnumerable<T>.Destroy;
begin
inherited;
end;function TEnumerable<T>.GetEnumerator: TEnumerator<T>;
begin
Result := DoGetEnumerator;
end;function TEnumerable<T>.ToArray: TArray<T>;
var
buf: TList<T>;
x: T;
begin
buf := TList<T>.Create;
try
for x in Self do
buf.Add(x);
Result := buf.ToArray; // relies on TList<T>.ToArray override
finally
buf.Free;
end;
end;function TEnumerable<T>.ToArrayImpl(Count: Integer): TArray<T>;
var
x: T;
begin
// We assume our caller has passed correct Count
SetLength(Result, Count);
Count := 0;
for x in Self do
begin
Result[Count] := x;
Inc(Count);
end;
end;{ TList<T> }
function TList<T>.GetCapacity: Integer;
begin
Result := Length(FItems); //3)디버깅 해보면 오류메새지가 여기서 나는것 같습니다
end;procedure TList<T>.SetCapacity(Value: Integer);
begin
if Value < Count then
Count := Value;
SetLength(FItems, Value);
end;procedure TList<T>.SetCount(Value: Integer);
begin
if Value < 0 then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if Value > Capacity then
SetCapacity(Value);
if Value < Count then
DeleteRange(Value, Count - Value);
FCount := Value;
end;function TList<T>.GetItem(Index: Integer): T;
begin
if (Index < 0) or (Index >= Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
Result := FItems[Index];
end;procedure TList<T>.SetItem(Index: Integer; const Value: T);
var
oldItem: T;
begin
if (Index < 0) or (Index >= Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);oldItem := FItems[Index];
FItems[Index] := Value;Notify(oldItem, cnRemoved);
Notify(Value, cnAdded);
end;procedure TList<T>.Grow(ACount: Integer);
var
newCount: Integer;
begin
newCount := Length(FItems);
if newCount = 0 then
newCount := ACount
else
repeat
newCount := newCount * 2;
if newCount < 0 then
OutOfMemoryError;
until newCount >= ACount;
Capacity := newCount;
end;procedure TList<T>.GrowCheck(ACount: Integer);
begin
if ACount > Length(FItems) then
Grow(ACount)
else if ACount < 0 then
OutOfMemoryError;
end;procedure TList<T>.Notify(const Item: T; Action: TCollectionNotification);
begin
if Assigned(FOnNotify) then
FOnNotify(Self, Item, Action);
end;procedure TList<T>.Pack;
begin
Pack(function (const Left, Right: T): Boolean
begin
Result := FComparer.Compare(Left, Right) = 0;
end);
end;procedure TList<T>.Pack(const IsEmpty: TEmptyFunc);
var
PackedCount : Integer;
StartIndex : Integer;
EndIndex : Integer;
begin
if FCount = 0 then
Exit;PackedCount := 0;
StartIndex := 0;
repeat
// Locate the first/next non-nil element in the list
// while (StartIndex < FCount) and (FComparer.Compare(FItems[StartIndex], Default(T)) = 0) do
while (StartIndex < FCount) and (IsEmpty(FItems[StartIndex], Default(T))) do
Inc(StartIndex);if StartIndex < FCount then // There is nothing more to do
begin
// Locate the next nil pointer
EndIndex := StartIndex;
// while (EndIndex < FCount) and (FComparer.Compare(FItems[EndIndex], Default(T)) <> 0) do
while (EndIndex < FCount) and not IsEmpty(FItems[EndIndex], Default(T)) do
Inc(EndIndex);
Dec(EndIndex);// Move this block of non-null items to the index recorded in PackedToCount:
// If this is a contiguous non-nil block at the start of the list then
// StartIndex and PackedToCount will be equal (and 0) so don't bother with the move.
if StartIndex > PackedCount then
FArrayManager.Move(FItems, StartIndex, PackedCount, EndIndex - StartIndex + 1);// Set the PackedToCount to reflect the number of items in the list
// that have now been packed.
Inc(PackedCount, EndIndex - StartIndex + 1);// Reset StartIndex to the element following EndIndex
StartIndex := EndIndex + 1;
end;
until StartIndex >= FCount;// Set Count so that the 'free' item
FCount := PackedCount;
end;constructor TList<T>.Create;
begin
Create(TComparer<T>.Default);
end;constructor TList<T>.Create(const AComparer: IComparer<T>);
begin
inherited Create;
{$IF Defined(WEAKREF)}
if System.HasWeakRef(T) then
FArrayManager := TManualArrayManager<T>.Create
else
{$ENDIF}
FArrayManager := TMoveArrayManager<T>.Create;
FComparer := AComparer;
if FComparer = nil then
FComparer := TComparer<T>.Default;
end;constructor TList<T>.Create(const Collection: TEnumerable<T>);
begin
inherited Create;
{$IF Defined(WEAKREF)}
if System.HasWeakRef(T) then
FArrayManager := TManualArrayManager<T>.Create
else
{$ENDIF}
FArrayManager := TMoveArrayManager<T>.Create;
FComparer := TComparer<T>.Default;
InsertRange(0, Collection);
end;destructor TList<T>.Destroy;
begin
Capacity := 0;
FArrayManager.Free;
inherited;
end;class procedure TList<T>.Error(const Msg: string; Data: NativeInt);
begin
raise EListError.CreateFmt(Msg, [Data]) at ReturnAddress;
end;{$IFNDEF NEXTGEN}
class procedure TList<T>.Error(Msg: PResStringRec; Data: NativeInt);
begin
raise EListError.CreateFmt(LoadResString(Msg), [Data]) at ReturnAddress;
end;
{$ENDIF NEXTGEN}function TList<T>.DoGetEnumerator: TEnumerator<T>;
begin
Result := GetEnumerator;
end;function TList<T>.Add(const Value: T): Integer;
begin
GrowCheck(Count + 1);
Result := Count;
FItems[Count] := Value;
Inc(FCount);
Notify(Value, cnAdded);
end;
procedure TList<T>.AddRange(const Values: array of T);
begin
InsertRange(Count, Values);
end;procedure TList<T>.AddRange(const Collection: IEnumerable<T>);
begin
InsertRange(Count, Collection);
end;procedure TList<T>.AddRange(const Collection: TEnumerable<T>);
begin
InsertRange(Count, Collection);
end;function TList<T>.BinarySearch(const Item: T; out Index: Integer): Boolean;
begin
Result := TArray.BinarySearch<T>(FItems, Item, Index, FComparer, 0, Count);
end;function TList<T>.BinarySearch(const Item: T; out Index: Integer;
const AComparer: IComparer<T>): Boolean;
begin
Result := TArray.BinarySearch<T>(FItems, Item, Index, AComparer, 0, Count);
end;procedure TList<T>.Insert(Index: Integer; const Value: T);
begin
if (Index < 0) or (Index > Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);GrowCheck(Count + 1);
if Index <> Count then
begin
FArrayManager.Move(FItems, Index, Index + 1, Count - Index);
FArrayManager.Finalize(FItems, Index, 1);
end;
FItems[Index] := Value;
Inc(FCount);
Notify(Value, cnAdded);
end;procedure TList<T>.InsertRange(Index: Integer; const Values: array of T);
var
I: Integer;
begin
if (Index < 0) or (Index > Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);GrowCheck(Count + Length(Values));
if Index <> Count then
begin
FArrayManager.Move(FItems, Index, Index + Length(Values), Count - Index);
FArrayManager.Finalize(FItems, Index, Length(Values));
end;for I := 0 to Length(Values) - 1 do
FItems[Index + I] := Values[I];Inc(FCount, Length(Values));
for I := 0 to Length(Values) - 1 do
Notify(Values[I], cnAdded);
end;procedure TList<T>.InsertRange(Index: Integer; const Collection: IEnumerable<T>);
var
item: T;
begin
for item in Collection do
begin
Insert(Index, item);
Inc(Index);
end;
end;procedure TList<T>.InsertRange(Index: Integer; const Collection: TEnumerable<T>);
var
item: T;
begin
for item in Collection do
begin
Insert(Index, item);
Inc(Index);
end;
end;function TList<T>.ItemValue(const Item: T): NativeInt;
begin
case SizeOf(Item) of
1: Result := PByte(@Item)[0] shl 0;
2: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8;
3: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16;
{$IF SizeOf(IntPtr) <= 4}
else
Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24;
{$ELSE}
4: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24;
5: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24 +
IntPtr(PByte(@Item)[4]) shl 32;
6: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24 +
IntPtr(PByte(@Item)[4]) shl 32 + IntPtr(PByte(@Item)[5]) shl 40;
7: Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24 +
IntPtr(PByte(@Item)[4]) shl 32 + IntPtr(PByte(@Item)[5]) shl 40 + IntPtr(PByte(@Item)[6]) shl 48;
else
Result := PByte(@Item)[0] shl 0 + PByte(@Item)[1] shl 8 + PByte(@Item)[2] shl 16 + PByte(@Item)[3] shl 24 +
IntPtr(PByte(@Item)[4]) shl 32 + IntPtr(PByte(@Item)[5]) shl 40 + IntPtr(PByte(@Item)[6]) shl 48 + IntPtr(PByte(@Item)[7]) shl 56;
{$ENDIF}
end;
end;procedure TList<T>.Exchange(Index1, Index2: Integer);
var
temp: T;
begin
temp := FItems[Index1];
FItems[Index1] := FItems[Index2];
FItems[Index2] := temp;
end;function TList<T>.Extract(const Value: T): T;
begin
Result := ExtractItem(Value, TDirection.FromBeginning);
end;function TList<T>.ExtractItem(const Value: T; Direction: TDirection): T;
var
index: Integer;
begin
index := IndexOfItem(Value, Direction);
if index < 0 then
Result := Default(T)
else
begin
Result := FItems[index];
DoDelete(index, cnExtracted);
end;
end;function TList<T>.First: T;
begin
Result := Items[0];
end;function TList<T>.Remove(const Value: T): Integer;
begin
Result := IndexOf(Value);
if Result >= 0 then
Delete(Result);
end;function TList<T>.RemoveItem(const Value: T; Direction: TDirection): Integer;
begin
Result := IndexOfItem(Value, Direction);
if Result >= 0 then
Delete(Result);
end;procedure TList<T>.DoDelete(Index: Integer; Notification: TCollectionNotification);
var
oldItem: T;
begin
if (Index < 0) or (Index >= Count) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
oldItem := FItems[Index];
FItems[Index] := Default(T);
Dec(FCount);
if Index <> Count then
begin
FArrayManager.Move(FItems, Index + 1, Index, Count - Index);
FArrayManager.Finalize(FItems, Count, 1);
end;
Notify(oldItem, Notification);
end;procedure TList<T>.Delete(Index: Integer);
begin
DoDelete(Index, cnRemoved);
end;procedure TList<T>.DeleteRange(AIndex, ACount: Integer);
var
oldItems: array of T;
tailCount, I: Integer;
begin
if (AIndex < 0) or (ACount < 0) or (AIndex + ACount > Count)
or (AIndex + ACount < 0) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if ACount = 0 then
Exit;
SetLength(oldItems, ACount);
FArrayManager.Move(FItems, oldItems, AIndex, 0, ACount);tailCount := Count - (AIndex + ACount);
if tailCount > 0 then
begin
FArrayManager.Move(FItems, AIndex + ACount, AIndex, tailCount);
FArrayManager.Finalize(FItems, Count - ACount, ACount);
end else
FArrayManager.Finalize(FItems, AIndex, ACount);Dec(FCount, ACount);
for I := 0 to Length(oldItems) - 1 do
Notify(oldItems[I], cnRemoved);
end;procedure TList<T>.Clear;
begin
Count := 0;
Capacity := 0;
end;function TList<T>.Expand: TList<T>;
begin
if FCount = Length(FItems) then
GrowCheck(FCount + 1);
Result := Self;
end;function TList<T>.Contains(const Value: T): Boolean;
begin
Result := IndexOf(Value) >= 0;
end;function TList<T>.IndexOf(const Value: T): Integer;
var
i: Integer;
begin
for i := 0 to Count - 1 do
if FComparer.Compare(FItems[i], Value) = 0 then
Exit(i);
Result := -1;
end;function TList<T>.IndexOfItem(const Value: T; Direction: TDirection): Integer;
var
P: T;
i: Integer;
begin
if Direction = TDirection.FromBeginning then
Result := IndexOf(Value)
else
begin
if Count > 0 then
begin
for i := Count - 1 downto 0 do
if FComparer.Compare(FItems[i], Value) = 0 then
Exit(i);
end;
Result := -1;
end;
end;function TList<T>.Last: T;
begin
Result := Items[Count - 1];
end;function TList<T>.LastIndexOf(const Value: T): Integer;
var
i: Integer;
begin
for i := Count - 1 downto 0 do
if FComparer.Compare(FItems[i], Value) = 0 then
Exit(i);
Result := -1;
end;procedure TList<T>.Move(CurIndex, NewIndex: Integer);
var
temp: T;
begin
if CurIndex = NewIndex then
Exit;
if (NewIndex < 0) or (NewIndex >= FCount) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);temp := FItems[CurIndex];
FItems[CurIndex] := Default(T);
if CurIndex < NewIndex then
FArrayManager.Move(FItems, CurIndex + 1, CurIndex, NewIndex - CurIndex)
else
FArrayManager.Move(FItems, NewIndex, NewIndex + 1, CurIndex - NewIndex);FArrayManager.Finalize(FItems, NewIndex, 1);
FItems[NewIndex] := temp;
end;procedure TList<T>.Reverse;
var
tmp: T;
b, e: Integer;
begin
b := 0;
e := Count - 1;
while b < e do
begin
tmp := FItems[b];
FItems[b] := FItems[e];
FItems[e] := tmp;
Inc(b);
Dec(e);
end;
end;procedure TList<T>.Sort;
begin
TArray.Sort<T>(FItems, FComparer, 0, Count);
end;procedure TList<T>.Sort(const AComparer: IComparer<T>);
begin
TArray.Sort<T>(FItems, AComparer, 0, Count);
end;function TList<T>.ToArray: TArray<T>;
var
i: Integer;
begin
SetLength(Result, Count);
for i := 0 to Count - 1 do
Result[i] := Items[i];
end;procedure TList<T>.TrimExcess;
begin
Capacity := Count;
end;function TList<T>.GetEnumerator: TEnumerator;
begin
Result := TEnumerator.Create(Self);
end;{ TList<T>.TEnumerator }
constructor TList<T>.TEnumerator.Create(const AList: TList<T>);
begin
inherited Create;
FList := AList;
FIndex := -1;
end;function TList<T>.TEnumerator.DoGetCurrent: T;
begin
Result := GetCurrent;
end;function TList<T>.TEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;function TList<T>.TEnumerator.GetCurrent: T;
begin
Result := FList[FIndex];
end;function TList<T>.TEnumerator.MoveNext: Boolean;
begin
if FIndex >= FList.Count then
Exit(False);
Inc(FIndex);
Result := FIndex < FList.Count;
end;
{ TQueue<T> }procedure TQueue<T>.Notify(const Item: T; Action: TCollectionNotification);
begin
if Assigned(FOnNotify) then
FOnNotify(Self, Item, Action);
end;constructor TQueue<T>.Create;
begin
inherited Create;
{$IF Defined(WEAKREF)}
if System.HasWeakRef(T) then
FArrayManager := TManualArrayManager<T>.Create
else
{$ENDIF}
FArrayManager := TMoveArrayManager<T>.Create;
end;function TQueue<T>.Dequeue: T;
begin
Result := DoDequeue(cnRemoved);
end;destructor TQueue<T>.Destroy;
begin
Clear;
FArrayManager.Free;
inherited;
end;function TQueue<T>.DoGetEnumerator: TEnumerator<T>;
begin
Result := GetEnumerator;
end;procedure TQueue<T>.DoSetCapacity(Value: Integer);
begin
if Value < Count then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
SetCapacity(Value);
end;procedure TQueue<T>.Enqueue(const Value: T);
begin
if Count = Length(FItems) then
Grow;
FItems[FHead] := Value;
FHead := (FHead + 1) mod Length(FItems);
Inc(FCount);
Notify(Value, cnAdded);
end;function TQueue<T>.Extract: T;
begin
Result := DoDequeue(cnExtracted);
end;constructor TQueue<T>.Create(const Collection: TEnumerable<T>);
var
item: T;
begin
inherited Create;
{$IF Defined(WEAKREF)}
if System.HasWeakRef(T) then
FArrayManager := TManualArrayManager<T>.Create
else
{$ENDIF}
FArrayManager := TMoveArrayManager<T>.Create;
for item in Collection do
Enqueue(item);
end;function TQueue<T>.DoDequeue(Notification: TCollectionNotification): T;
begin
if Count = 0 then
raise EListError.CreateRes(@SUnbalancedOperation);
Result := FItems[FTail];
FItems[FTail] := Default(T);
FTail := (FTail + 1) mod Length(FItems);
Dec(FCount);
Notify(Result, Notification);
end;function TQueue<T>.Peek: T;
begin
if Count = 0 then
raise EListError.CreateRes(@SUnbalancedOperation);
Result := FItems[FTail];
end;procedure TQueue<T>.Clear;
begin
while Count > 0 do
Dequeue;
FHead := 0;
FTail := 0;
FCount := 0;
end;function TQueue<T>.ToArray: TArray<T>;
begin
Result := ToArrayImpl(Count);
end;procedure TQueue<T>.TrimExcess;
begin
SetCapacity(Count);
end;procedure TQueue<T>.SetCapacity(Value: Integer);
var
tailCount, offset: Integer;
begin
offset := Value - Length(FItems);
if offset = 0 then
Exit;
// If head <= tail, then part of the queue wraps around
// the end of the array; don't introduce a gap in the queue.
if (FHead < FTail) or ((FHead = FTail) and (Count > 0)) then
tailCount := Length(FItems) - FTail
else
tailCount := 0;
if offset > 0 then
SetLength(FItems, Value);
if tailCount > 0 then
begin
FArrayManager.Move(FItems, FTail, FTail + offset, tailCount);
if offset > 0 then
FArrayManager.Finalize(FItems, FTail, offset)
else if offset < 0 then
FArrayManager.Finalize(FItems, Count, (- offset));
Inc(FTail, offset);
end
else if FTail > 0 then
begin
if Count > 0 then
begin
FArrayManager.Move(FItems, FTail, 0, Count);
FArrayManager.Finalize(FItems, FCount, FTail);
end;
Dec(FHead, FTail);
FTail := 0;
end;
if offset < 0 then
begin
SetLength(FItems, Value);
if Value = 0 then
FHead := 0
else
FHead := FHead mod Length(FItems);
end;
end;procedure TQueue<T>.Grow;
var
newCap: Integer;
begin
newCap := Length(FItems) * 2;
if newCap = 0 then
newCap := 4
else if newCap < 0 then
OutOfMemoryError;
SetCapacity(newCap);
end;function TQueue<T>.GetCapacity: Integer;
begin
Result := Length(FItems);
end;function TQueue<T>.GetEnumerator: TEnumerator;
begin
Result := TEnumerator.Create(Self);
end;{ TQueue<T>.TEnumerator }
constructor TQueue<T>.TEnumerator.Create(const AQueue: TQueue<T>);
begin
inherited Create;
FQueue := AQueue;
FIndex := -1;
end;function TQueue<T>.TEnumerator.DoGetCurrent: T;
begin
Result := GetCurrent;
end;function TQueue<T>.TEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;function TQueue<T>.TEnumerator.GetCurrent: T;
begin
Result := FQueue.FItems[(FQueue.FTail + FIndex) mod Length(FQueue.FItems)];
end;function TQueue<T>.TEnumerator.MoveNext: Boolean;
begin
if FIndex >= FQueue.Count then
Exit(False);
Inc(FIndex);
Result := FIndex < FQueue.Count;
end;{ TStack<T> }
procedure TStack<T>.Notify(const Item: T; Action: TCollectionNotification);
begin
if Assigned(FOnNotify) then
FOnNotify(Self, Item, Action);
end;constructor TStack<T>.Create(const Collection: TEnumerable<T>);
var
item: T;
begin
inherited Create;
for item in Collection do
Push(item);
end;destructor TStack<T>.Destroy;
begin
Clear;
inherited;
end;function TStack<T>.DoGetEnumerator: TEnumerator<T>;
begin
Result := GetEnumerator;
end;procedure TStack<T>.Grow;
var
newCap: Integer;
begin
newCap := Length(FItems) * 2;
if newCap = 0 then
newCap := 4
else if newCap < 0 then
OutOfMemoryError;
SetLength(FItems, newCap);
end;procedure TStack<T>.Push(const Value: T);
begin
if Count = Length(FItems) then
Grow;
FItems[Count] := Value;
Inc(FCount);
Notify(Value, cnAdded);
end;function TStack<T>.DoPop(Notification: TCollectionNotification): T;
begin
if Count = 0 then
raise EListError.CreateRes(@SUnbalancedOperation);
Dec(FCount);
Result := FItems[Count];
FItems[Count] := Default(T);
Notify(Result, Notification);
end;procedure TStack<T>.DoSetCapacity(Value: Integer);
begin
if Value < Count then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
SetLength(FItems, Value);
end;function TStack<T>.Extract: T;
begin
Result := DoPop(cnExtracted);
end;function TStack<T>.Peek: T;
begin
if Count = 0 then
raise EListError.CreateRes(@SUnbalancedOperation);
Result := FItems[Count - 1];
end;function TStack<T>.Pop: T;
begin
Result := DoPop(cnRemoved);
end;procedure TStack<T>.Clear;
begin
while Count > 0 do
Pop;
SetLength(FItems, 0);
end;function TStack<T>.ToArray: TArray<T>;
begin
Result := ToArrayImpl(Count);
end;procedure TStack<T>.TrimExcess;
begin
SetLength(FItems, Count);
end;function TStack<T>.GetCapacity: Integer;
begin
Result := Length(FItems);
end;function TStack<T>.GetEnumerator: TEnumerator;
begin
Result := TEnumerator.Create(Self);
end;constructor TStack<T>.TEnumerator.Create(const AStack: TStack<T>);
begin
inherited Create;
FStack := AStack;
FIndex := -1;
end;function TStack<T>.TEnumerator.DoGetCurrent: T;
begin
Result := GetCurrent;
end;function TStack<T>.TEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;function TStack<T>.TEnumerator.GetCurrent: T;
begin
Result := FStack.FItems[FIndex];
end;function TStack<T>.TEnumerator.MoveNext: Boolean;
begin
if FIndex >= FStack.Count then
Exit(False);
Inc(FIndex);
Result := FIndex < FStack.Count;
end;{ TPair<TKey,TValue> }
constructor TPair<TKey,TValue>.Create(const AKey: TKey; const AValue: TValue);
begin
Key := AKey;
Value := AValue;
end;{ TDictionary<TKey,TValue> }
const
EMPTY_HASH = -1;procedure TDictionary<TKey,TValue>.Rehash(NewCapPow2: Integer);
var
oldItems, newItems: TItemArray;
i: Integer;
begin
if NewCapPow2 = Length(FItems) then
Exit
else if NewCapPow2 < 0 then
OutOfMemoryError;
oldItems := FItems;
SetLength(newItems, NewCapPow2);
for i := 0 to Length(newItems) - 1 do
newItems[i].HashCode := EMPTY_HASH;
FItems := newItems;
FGrowThreshold := NewCapPow2 shr 1 + NewCapPow2 shr 2; // 75%
for i := 0 to Length(oldItems) - 1 do
if oldItems[i].HashCode <> EMPTY_HASH then
RehashAdd(oldItems[i].HashCode, oldItems[i].Key, oldItems[i].Value);
end;procedure TDictionary<TKey,TValue>.SetCapacity(ACapacity: Integer);
var
newCap: Integer;
begin
if ACapacity < Count then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if ACapacity = 0 then
Rehash(0)
else
begin
newCap := 4;
while newCap < ACapacity do
newCap := newCap shl 1;
Rehash(newCap);
end
end;procedure TDictionary<TKey,TValue>.Grow;
var
newCap: Integer;
begin
newCap := Length(FItems) * 2;
if newCap = 0 then
newCap := 4;
Rehash(newCap);
end;function TDictionary<TKey,TValue>.GetBucketIndex(const Key: TKey; HashCode: Integer): Integer;
var
start, hc: Integer;
begin
if Length(FItems) = 0 then
Exit(not High(Integer));
start := HashCode and (Length(FItems) - 1);
Result := start;
while True do
begin
hc := FItems[Result].HashCode;
// Not found: return complement of insertion point.
if hc = EMPTY_HASH then
Exit(not Result);
// Found: return location.
if (hc = HashCode) and FComparer.Equals(FItems[Result].Key, Key) then
Exit(Result);
Inc(Result);
if Result >= Length(FItems) then
Result := 0;
end;
end;function TDictionary<TKey,TValue>.Hash(const Key: TKey): Integer;
const
PositiveMask = not Integer($80000000);
begin
// Double-Abs to avoid -MaxInt and MinInt problems.
// Not using compiler-Abs because we *must* get a positive integer;
// for compiler, Abs(Low(Integer)) is a null op.
Result := PositiveMask and ((PositiveMask and FComparer.GetHashCode(Key)) + 1);
end;function TDictionary<TKey,TValue>.GetItem(const Key: TKey): TValue;
var
index: Integer;
begin
index := GetBucketIndex(Key, Hash(Key));
if index < 0 then
raise EListError.CreateRes(@SGenericItemNotFound);
Result := FItems[index].Value;
end;procedure TDictionary<TKey,TValue>.SetItem(const Key: TKey; const Value: TValue);
var
index: Integer;
oldValue: TValue;
begin
index := GetBucketIndex(Key, Hash(Key));
if index < 0 then
raise EListError.CreateRes(@SGenericItemNotFound);
oldValue := FItems[index].Value;
FItems[index].Value := Value;
ValueNotify(oldValue, cnRemoved);
ValueNotify(Value, cnAdded);
end;procedure TDictionary<TKey,TValue>.RehashAdd(HashCode: Integer; const Key: TKey; const Value: TValue);
var
index: Integer;
begin
index := not GetBucketIndex(Key, HashCode);
FItems[index].HashCode := HashCode;
FItems[index].Key := Key;
FItems[index].Value := Value;
end;procedure TDictionary<TKey,TValue>.KeyNotify(const Key: TKey; Action: TCollectionNotification);
begin
if Assigned(FOnKeyNotify) then
FOnKeyNotify(Self, Key, Action);
end;procedure TDictionary<TKey,TValue>.ValueNotify(const Value: TValue; Action: TCollectionNotification);
begin
if Assigned(FOnValueNotify) then
FOnValueNotify(Self, Value, Action);
end;constructor TDictionary<TKey,TValue>.Create(ACapacity: Integer = 0);
begin
Create(ACapacity, nil);
end;constructor TDictionary<TKey,TValue>.Create(const AComparer: IEqualityComparer<TKey>);
begin
Create(0, AComparer);
end;constructor TDictionary<TKey,TValue>.Create(ACapacity: Integer; const AComparer: IEqualityComparer<TKey>);
var
cap: Integer;
begin
inherited Create;
if ACapacity < 0 then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
FComparer := AComparer;
if FComparer = nil then
FComparer := TEqualityComparer<TKey>.Default;
SetCapacity(ACapacity);
end;constructor TDictionary<TKey, TValue>.Create(const Collection: TEnumerable<TPair<TKey, TValue>>);
var
item: TPair<TKey,TValue>;
begin
Create(0, nil);
for item in Collection do
AddOrSetValue(item.Key, item.Value);
end;constructor TDictionary<TKey, TValue>.Create(const Collection: TEnumerable<TPair<TKey, TValue>>;
const AComparer: IEqualityComparer<TKey>);
var
item: TPair<TKey,TValue>;
begin
Create(0, AComparer);
for item in Collection do
AddOrSetValue(item.Key, item.Value);
end;destructor TDictionary<TKey,TValue>.Destroy;
begin
Clear;
FKeyCollection.Free;
FValueCollection.Free;
inherited;
end;procedure TDictionary<TKey,TValue>.Add(const Key: TKey; const Value: TValue);
var
index, hc: Integer;
begin
if Count >= FGrowThreshold then
Grow;
hc := Hash(Key);
index := GetBucketIndex(Key, hc);
if index >= 0 then
raise EListError.CreateRes(@SGenericDuplicateItem);
DoAdd(hc, not index, Key, Value);
end;function InCircularRange(Bottom, Item, TopInc: Integer): Boolean;
begin
Result := (Bottom < Item) and (Item <= TopInc) // normal
or (TopInc < Bottom) and (Item > Bottom) // top wrapped
or (TopInc < Bottom) and (Item <= TopInc) // top and item wrapped
end;function TDictionary<TKey,TValue>.DoRemove(const Key: TKey; HashCode: Integer;
Notification: TCollectionNotification): TValue;
var
gap, index, hc, bucket: Integer;
begin
index := GetBucketIndex(Key, HashCode);
if index < 0 then
Exit(Default(TValue));
// Removing item from linear probe hash table is moderately
// tricky. We need to fill in gaps, which will involve moving items
// which may not even hash to the same location.
// Knuth covers it well enough in Vol III. 6.4.; but beware, Algorithm R
// (2nd ed) has a bug: step R4 should go to step R1, not R2 (already errata'd).
// My version does linear probing forward, not backward, however.
// gap refers to the hole that needs filling-in by shifting items down.
// index searches for items that have been probed out of their slot,
// but being careful not to move items if their bucket is between
// our gap and our index (so that they'd be moved before their bucket).
// We move the item at index into the gap, whereupon the new gap is
// at the index. If the index hits a hole, then we're done.
// If our load factor was exactly 1, we'll need to hit this hole
// in order to terminate. Shouldn't normally be necessary, though.
FItems[index].HashCode := EMPTY_HASH;
Result := FItems[index].Value;
gap := index;
while True do
begin
Inc(index);
if index = Length(FItems) then
index := 0;
hc := FItems[index].HashCode;
if hc = EMPTY_HASH then
Break;
bucket := hc and (Length(FItems) - 1);
if not InCircularRange(gap, bucket, index) then
begin
FItems[gap] := FItems[index];
gap := index;
// The gap moved, but we still need to find it to terminate.
FItems[gap].HashCode := EMPTY_HASH;
end;
end;
FItems[gap].HashCode := EMPTY_HASH;
FItems[gap].Key := Default(TKey);
FItems[gap].Value := Default(TValue);
Dec(FCount);
KeyNotify(Key, Notification);
ValueNotify(Result, Notification);
end;procedure TDictionary<TKey,TValue>.Remove(const Key: TKey);
begin
DoRemove(Key, Hash(Key), cnRemoved);
end;function TDictionary<TKey,TValue>.ExtractPair(const Key: TKey): TPair<TKey,TValue>;
var
hc, index: Integer;
begin
hc := Hash(Key);
index := GetBucketIndex(Key, hc);
if index < 0 then
Exit(TPair<TKey,TValue>.Create(Key, Default(TValue)));
Result := TPair<TKey,TValue>.Create(Key, DoRemove(Key, hc, cnExtracted));
end;procedure TDictionary<TKey,TValue>.Clear;
var
i: Integer;
oldItems: TItemArray;
begin
oldItems := FItems;
FCount := 0;
SetLength(FItems, 0);
SetCapacity(0);
FGrowThreshold := 0;
for i := 0 to Length(oldItems) - 1 do
begin
if oldItems[i].HashCode = EMPTY_HASH then
Continue;
KeyNotify(oldItems[i].Key, cnRemoved);
ValueNotify(oldItems[i].Value, cnRemoved);
end;
end;function TDictionary<TKey, TValue>.ToArray: TArray<TPair<TKey,TValue>>;
begin
Result := ToArrayImpl(Count);
end;procedure TDictionary<TKey,TValue>.TrimExcess;
begin
// Ensure at least one empty slot for GetBucketIndex to terminate.
SetCapacity(Count + 1);
end;function TDictionary<TKey,TValue>.TryGetValue(const Key: TKey; out Value: TValue): Boolean;
var
index: Integer;
begin
index := GetBucketIndex(Key, Hash(Key));
Result := index >= 0;
if Result then
Value := FItems[index].Value
else
Value := Default(TValue);
end;procedure TDictionary<TKey,TValue>.DoAdd(HashCode, Index: Integer; const Key: TKey; const Value: TValue);
begin
FItems[Index].HashCode := HashCode;
FItems[Index].Key := Key;
FItems[Index].Value := Value;
Inc(FCount);
KeyNotify(Key, cnAdded);
ValueNotify(Value, cnAdded);
end;function TDictionary<TKey, TValue>.DoGetEnumerator: TEnumerator<TPair<TKey, TValue>>;
begin
Result := GetEnumerator;
end;procedure TDictionary<TKey,TValue>.DoSetValue(Index: Integer; const Value: TValue);
var
oldValue: TValue;
begin
oldValue := FItems[Index].Value;
FItems[Index].Value := Value;
ValueNotify(oldValue, cnRemoved);
ValueNotify(Value, cnAdded);
end;procedure TDictionary<TKey,TValue>.AddOrSetValue(const Key: TKey; const Value: TValue);
var
hc: Integer;
index: Integer;
begin
hc := Hash(Key);
index := GetBucketIndex(Key, hc);
if index >= 0 then
DoSetValue(index, Value)
else
begin
// We only grow if we are inserting a new value.
if Count >= FGrowThreshold then
begin
Grow;
// We need a new Bucket Index because the array has grown.
index := GetBucketIndex(Key, hc);
end;
DoAdd(hc, not index, Key, Value);
end;
end;function TDictionary<TKey,TValue>.ContainsKey(const Key: TKey): Boolean;
begin
Result := GetBucketIndex(Key, Hash(Key)) >= 0;
end;function TDictionary<TKey,TValue>.ContainsValue(const Value: TValue): Boolean;
var
i: Integer;
c: IEqualityComparer<TValue>;
begin
c := TEqualityComparer<TValue>.Default;for i := 0 to Length(FItems) - 1 do
if (FItems[i].HashCode <> EMPTY_HASH) and c.Equals(FItems[i].Value, Value) then
Exit(True);
Result := False;
end;function TDictionary<TKey,TValue>.GetEnumerator: TPairEnumerator;
begin
Result := TPairEnumerator.Create(Self);
end;function TDictionary<TKey,TValue>.GetKeys: TKeyCollection;
begin
if FKeyCollection = nil then
FKeyCollection := TKeyCollection.Create(Self);
Result := FKeyCollection;
end;function TDictionary<TKey,TValue>.GetValues: TValueCollection;
begin
if FValueCollection = nil then
FValueCollection := TValueCollection.Create(Self);
Result := FValueCollection;
end;// Pairs
constructor TDictionary<TKey,TValue>.TPairEnumerator.Create(const ADictionary: TDictionary<TKey,TValue>);
begin
inherited Create;
FIndex := -1;
FDictionary := ADictionary;
end;function TDictionary<TKey, TValue>.TPairEnumerator.DoGetCurrent: TPair<TKey, TValue>;
begin
Result := GetCurrent;
end;function TDictionary<TKey, TValue>.TPairEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;function TDictionary<TKey,TValue>.TPairEnumerator.GetCurrent: TPair<TKey,TValue>;
begin
Result.Key := FDictionary.FItems[FIndex].Key;
Result.Value := FDictionary.FItems[FIndex].Value;
end;function TDictionary<TKey,TValue>.TPairEnumerator.MoveNext: Boolean;
begin
while FIndex < Length(FDictionary.FItems) - 1 do
begin
Inc(FIndex);
if FDictionary.FItems[FIndex].HashCode <> EMPTY_HASH then
Exit(True);
end;
Result := False;
end;// Keys
constructor TDictionary<TKey,TValue>.TKeyEnumerator.Create(const ADictionary: TDictionary<TKey,TValue>);
begin
inherited Create;
FIndex := -1;
FDictionary := ADictionary;
end;function TDictionary<TKey, TValue>.TKeyEnumerator.DoGetCurrent: TKey;
begin
Result := GetCurrent;
end;function TDictionary<TKey, TValue>.TKeyEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;function TDictionary<TKey,TValue>.TKeyEnumerator.GetCurrent: TKey;
begin
Result := FDictionary.FItems[FIndex].Key;
end;function TDictionary<TKey,TValue>.TKeyEnumerator.MoveNext: Boolean;
begin
while FIndex < Length(FDictionary.FItems) - 1 do
begin
Inc(FIndex);
if FDictionary.FItems[FIndex].HashCode <> EMPTY_HASH then
Exit(True);
end;
Result := False;
end;// Values
constructor TDictionary<TKey,TValue>.TValueEnumerator.Create(const ADictionary: TDictionary<TKey,TValue>);
begin
inherited Create;
FIndex := -1;
FDictionary := ADictionary;
end;function TDictionary<TKey, TValue>.TValueEnumerator.DoGetCurrent: TValue;
begin
Result := GetCurrent;
end;function TDictionary<TKey, TValue>.TValueEnumerator.DoMoveNext: Boolean;
begin
Result := MoveNext;
end;function TDictionary<TKey,TValue>.TValueEnumerator.GetCurrent: TValue;
begin
Result := FDictionary.FItems[FIndex].Value;
end;function TDictionary<TKey,TValue>.TValueEnumerator.MoveNext: Boolean;
begin
while FIndex < Length(FDictionary.FItems) - 1 do
begin
Inc(FIndex);
if FDictionary.FItems[FIndex].HashCode <> EMPTY_HASH then
Exit(True);
end;
Result := False;
end;{ TObjectList<T> }
constructor TObjectList<T>.Create(AOwnsObjects: Boolean);
begin
inherited Create;
FOwnsObjects := AOwnsObjects;
end;constructor TObjectList<T>.Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean);
begin
inherited Create(AComparer);
FOwnsObjects := AOwnsObjects;
end;constructor TObjectList<T>.Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean);
begin
inherited Create(Collection);
FOwnsObjects := AOwnsObjects;
end;procedure TObjectList<T>.Notify(const Value: T; Action: TCollectionNotification);
begin
inherited;
if OwnsObjects and (Action = cnRemoved) then
Value.DisposeOf;
end;{ TObjectQueue<T> }
constructor TObjectQueue<T>.Create(AOwnsObjects: Boolean);
begin
inherited Create;
FOwnsObjects := AOwnsObjects;
end;constructor TObjectQueue<T>.Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean);
begin
inherited Create(Collection);
FOwnsObjects := AOwnsObjects;
end;procedure TObjectQueue<T>.Dequeue;
begin
inherited Dequeue;
end;procedure TObjectQueue<T>.Notify(const Value: T; Action: TCollectionNotification);
begin
inherited;
if OwnsObjects and (Action = cnRemoved) then
Value.DisposeOf;
end;{ TObjectStack<T> }
constructor TObjectStack<T>.Create(AOwnsObjects: Boolean);
begin
inherited Create;
FOwnsObjects := AOwnsObjects;
end;constructor TObjectStack<T>.Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean);
begin
inherited Create(Collection);
FOwnsObjects := AOwnsObjects;
end;procedure TObjectStack<T>.Notify(const Value: T; Action: TCollectionNotification);
begin
inherited;
if OwnsObjects and (Action = cnRemoved) then
Value.DisposeOf;
end;procedure TObjectStack<T>.Pop;
begin
inherited Pop;
end;{ TObjectDictionary<TKey,TValue> }
procedure TObjectDictionary<TKey,TValue>.KeyNotify(const Key: TKey; Action: TCollectionNotification);
begin
inherited;
if (Action = cnRemoved) and (doOwnsKeys in FOwnerships) then
PObject(@Key)^.DisposeOf;
end;procedure TObjectDictionary<TKey,TValue>.ValueNotify(const Value: TValue; Action: TCollectionNotification);
begin
inherited;
if (Action = cnRemoved) and (doOwnsValues in FOwnerships) then
PObject(@Value)^.DisposeOf;
end;constructor TObjectDictionary<TKey,TValue>.Create(Ownerships: TDictionaryOwnerships;
ACapacity: Integer = 0);
begin
Create(Ownerships, ACapacity, nil);
end;constructor TObjectDictionary<TKey,TValue>.Create(Ownerships: TDictionaryOwnerships;
const AComparer: IEqualityComparer<TKey>);
begin
Create(Ownerships, 0, AComparer);
end;constructor TObjectDictionary<TKey,TValue>.Create(Ownerships: TDictionaryOwnerships;
ACapacity: Integer; const AComparer: IEqualityComparer<TKey>);
begin
inherited Create(ACapacity, AComparer);
if doOwnsKeys in Ownerships then
begin
if (TypeInfo(TKey) = nil) or (PTypeInfo(TypeInfo(TKey))^.Kind <> tkClass) then
raise EInvalidCast.CreateRes(@SInvalidCast);
end;if doOwnsValues in Ownerships then
begin
if (TypeInfo(TValue) = nil) or (PTypeInfo(TypeInfo(TValue))^.Kind <> tkClass) then
raise EInvalidCast.CreateRes(@SInvalidCast);
end;
FOwnerships := Ownerships;
end;{ TDictionary<TKey, TValue>.TValueCollection }
constructor TDictionary<TKey, TValue>.TValueCollection.Create(const ADictionary: TDictionary<TKey, TValue>);
begin
inherited Create;
FDictionary := ADictionary;
end;function TDictionary<TKey, TValue>.TValueCollection.DoGetEnumerator: TEnumerator<TValue>;
begin
Result := GetEnumerator;
end;function TDictionary<TKey, TValue>.TValueCollection.GetCount: Integer;
begin
Result := FDictionary.Count;
end;function TDictionary<TKey, TValue>.TValueCollection.GetEnumerator: TValueEnumerator;
begin
Result := TValueEnumerator.Create(FDictionary);
end;function TDictionary<TKey, TValue>.TValueCollection.ToArray: TArray<TValue>;
begin
Result := ToArrayImpl(FDictionary.Count);
end;{ TDictionary<TKey, TValue>.TKeyCollection }
constructor TDictionary<TKey, TValue>.TKeyCollection.Create(
const ADictionary: TDictionary<TKey, TValue>);
begin
inherited Create;
FDictionary := ADictionary;
end;function TDictionary<TKey, TValue>.TKeyCollection.DoGetEnumerator: TEnumerator<TKey>;
begin
Result := GetEnumerator;
end;function TDictionary<TKey, TValue>.TKeyCollection.GetCount: Integer;
begin
Result := FDictionary.Count;
end;function TDictionary<TKey, TValue>.TKeyCollection.GetEnumerator: TKeyEnumerator;
begin
Result := TKeyEnumerator.Create(FDictionary);
end;function TDictionary<TKey, TValue>.TKeyCollection.ToArray: TArray<TKey>;
begin
Result := ToArrayImpl(FDictionary.Count);
end;{ TThreadedQueue<T> }
constructor TThreadedQueue<T>.Create(AQueueDepth: Integer = 10; PushTimeout: LongWord = INFINITE; PopTimeout: LongWord = INFINITE);
begin
inherited Create;
SetLength(FQueue, AQueueDepth);
FQueueLock := TObject.Create;
FQueueNotEmpty := TObject.Create;
FQueueNotFull := TObject.Create;
FPushTimeout := PushTimeout;
FPopTimeout := PopTimeout;
end;destructor TThreadedQueue<T>.Destroy;
begin
DoShutDown;
FQueueNotFull.Free;
FQueueNotEmpty.Free;
FQueueLock.Free;
inherited;
end;procedure TThreadedQueue<T>.Grow(ADelta: Integer);
begin
TMonitor.Enter(FQueueLock);
try
SetLength(FQueue, Length(FQueue) + ADelta);
finally
TMonitor.Exit(FQueueLock);
end;
TMonitor.PulseAll(FQueueNotFull);
end;function TThreadedQueue<T>.PopItem: T;
var
LQueueSize: Integer;
begin
PopItem(LQueueSize, Result);
end;function TThreadedQueue<T>.PopItem(var AQueueSize: Integer; var AItem: T): TWaitResult;
begin
AItem := Default(T);
TMonitor.Enter(FQueueLock);
try
Result := wrSignaled;
while (Result = wrSignaled) and (FQueueSize = 0) and not FShutDown do
if not TMonitor.Wait(FQueueNotEmpty, FQueueLock, FPopTimeout) then
Result := wrTimeout;if (FShutDown and (FQueueSize = 0)) or (Result <> wrSignaled) then
Exit;AItem := FQueue[FQueueOffset];
FQueue[FQueueOffset] := Default(T);
Dec(FQueueSize);
Inc(FQueueOffset);
Inc(FTotalItemsPopped);if FQueueOffset = Length(FQueue) then
FQueueOffset := 0;finally
AQueueSize := FQueueSize;
TMonitor.Exit(FQueueLock);
end;TMonitor.Pulse(FQueueNotFull);
end;function TThreadedQueue<T>.PopItem(var AItem: T): TWaitResult;
var
LQueueSize: Integer;
begin
Result := PopItem(LQueueSize, AItem);
end;function TThreadedQueue<T>.PopItem(var AQueueSize: Integer): T;
begin
PopItem(AQueueSize, Result);
end;function TThreadedQueue<T>.PushItem(const AItem: T): TWaitResult;
var
LQueueSize: Integer;
begin
Result := PushItem(AItem, LQueueSize);
end;function TThreadedQueue<T>.PushItem(const AItem: T; var AQueueSize: Integer): TWaitResult;
begin
TMonitor.Enter(FQueueLock);
try
Result := wrSignaled;
while (Result = wrSignaled) and (FQueueSize = Length(FQueue)) and not FShutDown do
if not TMonitor.Wait(FQueueNotFull, FQueueLock, FPushTimeout) then
Result := wrTimeout;if FShutDown or (Result <> wrSignaled) then
Exit;FQueue[(FQueueOffset + FQueueSize) mod Length(FQueue)] := AItem;
Inc(FQueueSize);
Inc(FTotalItemsPushed);finally
AQueueSize := FQueueSize;
TMonitor.Exit(FQueueLock);
end;TMonitor.Pulse(FQueueNotEmpty);
end;procedure TThreadedQueue<T>.DoShutDown;
begin
TMonitor.Enter(FQueueLock);
try
FShutDown := True;
finally
TMonitor.Exit(FQueueLock);
end;
TMonitor.PulseAll(FQueueNotFull);
TMonitor.PulseAll(FQueueNotEmpty);
end;{ TThreadList<T> }
procedure TThreadList<T>.Add(const Item: T);
begin
LockList;
try
if (Duplicates = dupAccept) or
(FList.IndexOf(Item) = -1) then
FList.Add(Item)
else if Duplicates = dupError then
raise EListError.CreateFmt(SDuplicateItem, [FList.ItemValue(Item)]);
finally
UnlockList;
end;
end;procedure TThreadList<T>.Clear;
begin
LockList;
try
FList.Clear;
finally
UnlockList;
end;
end;constructor TThreadList<T>.Create;
begin
inherited Create;
FLock := TObject.Create;
FList := TList<T>.Create;
FDuplicates := dupIgnore;
end;destructor TThreadList<T>.Destroy;
begin
LockList; // Make sure nobody else is inside the list.
try
FList.Free;
inherited Destroy;
finally
UnlockList;
FLock.Free;
end;
end;function TThreadList<T>.LockList: TList<T>;
begin
TMonitor.Enter(FLock);
Result := FList;
end;procedure TThreadList<T>.Remove(const Item: T);
begin
RemoveItem(Item, TDirection.FromBeginning);
end;procedure TThreadList<T>.RemoveItem(const Item: T; Direction: TDirection);
begin
LockList;
try
FList.RemoveItem(Item, Direction);
finally
UnlockList;
end;
end;procedure TThreadList<T>.UnlockList;
begin
TMonitor.Exit(FLock);
end;{ TArrayMoveManager<T> }
procedure TMoveArrayManager<T>.Finalize(var AArray: array of T; Index, Count: Integer);
begin
System.FillChar(AArray[Index], Count * SizeOf(T), 0);
end;procedure TMoveArrayManager<T>.Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer);
begin
System.Move(AArray[FromIndex], AArray[ToIndex], Count * SizeOf(T));
end;procedure TMoveArrayManager<T>.Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer);
begin
System.Move(FromArray[FromIndex], ToArray[ToIndex], Count * SizeOf(T));
end;{$IF Defined(WEAKREF)}
procedure TManualArrayManager<T>.Finalize(var AArray: array of T; Index, Count: Integer);
begin
System.Finalize(AArray[Index], Count);
System.FillChar(AArray[Index], Count * SizeOf(T), 0);
end;procedure TManualArrayManager<T>.Move(var AArray: array of T; FromIndex, ToIndex, Count: Integer);
var
I: Integer;
begin
if Count > 0 then
if FromIndex < ToIndex then
for I := Count - 1 downto 0 do
AArray[ToIndex + I] := AArray[FromIndex + I]
else if FromIndex > ToIndex then
for I := 0 to Count - 1 do
AArray[ToIndex + I] := AArray[FromIndex + I];
end;procedure TManualArrayManager<T>.Move(var FromArray, ToArray: array of T; FromIndex, ToIndex, Count: Integer);
var
I: Integer;
begin
if Count > 0 then
if FromIndex < ToIndex then
for I := Count - 1 downto 0 do
ToArray[ToIndex + I] := FromArray[FromIndex + I]
else if FromIndex > ToIndex then
for I := 0 to Count - 1 do
ToArray[ToIndex + I] := FromArray[FromIndex + I];
end;
{$ENDIF}end.
-
험프리
2017.09.29 09:10
우선 의심이 가는 부분이
제너릭으로 선언된 데이터타입과 생성한 데이터 타입이 다르네요.
선언
FTimeRanges: TList<TTimeRange>;
생성
FTimeRanges := TObjectList<TTimeRange>.Create;
특별한 이유가 있어서 이렇게 구현하셨을 것 같은데요. 영향이 있지 않을까요?위 데이터타입을 일치해 보시기 바랍니다. -
delphi
2017.09.29 10:21
혹 말씀한거 말고 수정해야 할 부분이 있을까요?
이소스 그대로 32-bit 윈도우에서는 정상 작동 합니다.
procedure TTimeCalculator.Init(ATimeRange: TTimeRange);
beginFTimeRanges.Clear; <===========디버깅 해보니 이부분에서 오류 .apk raised exception class segmentation fault (11). 발생
FTimeRanges.Add(ATimeRange);
end;
segmentation fault (11). 오류의 경우 잘못된 메모리 참조한 경우 발생합니다.
작성하신 코드의 일부를 첨부해 주시기 바랍니다.
특히, TList<T>를 생성한 코드와 호출한 메소드가 포함된 부분이 확인을 위해 필요합니다.