1*16467b97STreehugger Robot unit Antlr.Runtime.Tools;
2*16467b97STreehugger Robot (*
3*16467b97STreehugger Robot [The "BSD licence"]
4*16467b97STreehugger Robot Copyright (c) 2008 Erik van Bilsen
5*16467b97STreehugger Robot All rights reserved.
6*16467b97STreehugger Robot
7*16467b97STreehugger Robot Redistribution and use in source and binary forms, with or without
8*16467b97STreehugger Robot modification, are permitted provided that the following conditions
9*16467b97STreehugger Robot are met:
10*16467b97STreehugger Robot 1. Redistributions of source code MUST RETAIN the above copyright
11*16467b97STreehugger Robot notice, this list of conditions and the following disclaimer.
12*16467b97STreehugger Robot 2. Redistributions in binary form MUST REPRODUCE the above copyright
13*16467b97STreehugger Robot notice, this list of conditions and the following disclaimer in
14*16467b97STreehugger Robot the documentation and/or other materials provided with the
15*16467b97STreehugger Robot distribution.
16*16467b97STreehugger Robot 3. The name of the author may not be used to endorse or promote products
17*16467b97STreehugger Robot derived from this software without specific prior WRITTEN permission.
18*16467b97STreehugger Robot 4. Unless explicitly state otherwise, any contribution intentionally
19*16467b97STreehugger Robot submitted for inclusion in this work to the copyright owner or licensor
20*16467b97STreehugger Robot shall be under the terms and conditions of this license, without any
21*16467b97STreehugger Robot additional terms or conditions.
22*16467b97STreehugger Robot
23*16467b97STreehugger Robot THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24*16467b97STreehugger Robot IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25*16467b97STreehugger Robot OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26*16467b97STreehugger Robot IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27*16467b97STreehugger Robot INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28*16467b97STreehugger Robot NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29*16467b97STreehugger Robot DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30*16467b97STreehugger Robot THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31*16467b97STreehugger Robot (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32*16467b97STreehugger Robot THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33*16467b97STreehugger Robot *)
34*16467b97STreehugger Robot
35*16467b97STreehugger Robot interface
36*16467b97STreehugger Robot
37*16467b97STreehugger Robot {$IF CompilerVersion < 20}
38*16467b97STreehugger Robot {$MESSAGE ERROR 'You need Delphi 2009 or higher to use the Antlr runtime'}
39*16467b97STreehugger Robot {$IFEND}
40*16467b97STreehugger Robot
41*16467b97STreehugger Robot uses
42*16467b97STreehugger Robot Classes,
43*16467b97STreehugger Robot Generics.Defaults,
44*16467b97STreehugger Robot Generics.Collections;
45*16467b97STreehugger Robot
46*16467b97STreehugger Robot type
47*16467b97STreehugger Robot TSmallintArray = array of Smallint;
48*16467b97STreehugger Robot TSmallintMatrix = array of TSmallintArray;
49*16467b97STreehugger Robot TIntegerArray = array of Integer;
50*16467b97STreehugger Robot TUInt64Array = array of UInt64;
51*16467b97STreehugger Robot TStringArray = array of String;
52*16467b97STreehugger Robot
53*16467b97STreehugger Robot type
54*16467b97STreehugger Robot /// <summary>
55*16467b97STreehugger Robot /// Base interface for ANTLR objects
56*16467b97STreehugger Robot /// </summary>
57*16467b97STreehugger Robot IANTLRInterface = interface
58*16467b97STreehugger Robot ['{FA98F2EE-89D3-42A5-BC9C-1E8A9B278C3B}']
ToString()59*16467b97STreehugger Robot function ToString: String;
60*16467b97STreehugger Robot end;
61*16467b97STreehugger Robot TANTLRInterfaceArray = array of IANTLRInterface;
62*16467b97STreehugger Robot
63*16467b97STreehugger Robot type
64*16467b97STreehugger Robot /// <summary>
65*16467b97STreehugger Robot /// Gives access to implementing object
66*16467b97STreehugger Robot /// </summary>
67*16467b97STreehugger Robot IANTLRObject = interface
68*16467b97STreehugger Robot ['{E56CE28B-8D92-4961-90ED-418A1E8FEDF2}']
69*16467b97STreehugger Robot { Property accessors }
GetImplementor()70*16467b97STreehugger Robot function GetImplementor: TObject;
71*16467b97STreehugger Robot
72*16467b97STreehugger Robot { Properties }
73*16467b97STreehugger Robot property Implementor: TObject read GetImplementor;
74*16467b97STreehugger Robot end;
75*16467b97STreehugger Robot
76*16467b97STreehugger Robot type
77*16467b97STreehugger Robot /// <summary>
78*16467b97STreehugger Robot /// Base for ANTLR objects
79*16467b97STreehugger Robot /// </summary>
80*16467b97STreehugger Robot TANTLRObject = class(TInterfacedObject, IANTLRInterface, IANTLRObject)
81*16467b97STreehugger Robot protected
82*16467b97STreehugger Robot { IANTLRObject }
GetImplementor()83*16467b97STreehugger Robot function GetImplementor: TObject;
84*16467b97STreehugger Robot end;
85*16467b97STreehugger Robot
86*16467b97STreehugger Robot type
87*16467b97STreehugger Robot /// <summary>
88*16467b97STreehugger Robot /// Allows strings to be treated as object interfaces
89*16467b97STreehugger Robot /// </summary>
90*16467b97STreehugger Robot IANTLRString = interface(IANTLRInterface)
91*16467b97STreehugger Robot ['{1C7F2030-446C-4756-81E3-EC37E04E2296}']
92*16467b97STreehugger Robot { Property accessors }
GetValue()93*16467b97STreehugger Robot function GetValue: String;
94*16467b97STreehugger Robot procedure SetValue(const Value: String);
95*16467b97STreehugger Robot
96*16467b97STreehugger Robot { Properties }
97*16467b97STreehugger Robot property Value: String read GetValue write SetValue;
98*16467b97STreehugger Robot end;
99*16467b97STreehugger Robot
100*16467b97STreehugger Robot type
101*16467b97STreehugger Robot /// <summary>
102*16467b97STreehugger Robot /// Allows strings to be treated as object interfaces
103*16467b97STreehugger Robot /// </summary>
104*16467b97STreehugger Robot TANTLRString = class(TANTLRObject, IANTLRString)
105*16467b97STreehugger Robot strict private
106*16467b97STreehugger Robot FValue: String;
107*16467b97STreehugger Robot protected
108*16467b97STreehugger Robot { IANTLRString }
GetValue()109*16467b97STreehugger Robot function GetValue: String;
110*16467b97STreehugger Robot procedure SetValue(const Value: String);
111*16467b97STreehugger Robot public
112*16467b97STreehugger Robot constructor Create(const AValue: String);
113*16467b97STreehugger Robot
ToString()114*16467b97STreehugger Robot function ToString: String; override;
115*16467b97STreehugger Robot end;
116*16467b97STreehugger Robot
117*16467b97STreehugger Robot type
118*16467b97STreehugger Robot /// <summary>
119*16467b97STreehugger Robot /// Win32 version of .NET's ICloneable
120*16467b97STreehugger Robot /// </summary>
121*16467b97STreehugger Robot ICloneable = interface(IANTLRInterface)
122*16467b97STreehugger Robot ['{90240BF0-3A09-46B6-BC47-C13064809F97}']
123*16467b97STreehugger Robot { Methods }
Clone()124*16467b97STreehugger Robot function Clone: IANTLRInterface;
125*16467b97STreehugger Robot end;
126*16467b97STreehugger Robot
127*16467b97STreehugger Robot type
128*16467b97STreehugger Robot IList<T> = interface(IANTLRInterface)
129*16467b97STreehugger Robot ['{107DB2FE-A351-4F08-B9AD-E1BA8A4690FF}']
130*16467b97STreehugger Robot { Property accessors }
GetCapacity()131*16467b97STreehugger Robot function GetCapacity: Integer;
132*16467b97STreehugger Robot procedure SetCapacity(Value: Integer);
GetCount()133*16467b97STreehugger Robot function GetCount: Integer;
134*16467b97STreehugger Robot procedure SetCount(Value: Integer);
GetItem(Index: Integer)135*16467b97STreehugger Robot function GetItem(Index: Integer): T;
136*16467b97STreehugger Robot procedure SetItem(Index: Integer; const Value: T);
GetOnNotify()137*16467b97STreehugger Robot function GetOnNotify: TCollectionNotifyEvent<T>;
138*16467b97STreehugger Robot procedure SetOnNotify(Value: TCollectionNotifyEvent<T>);
139*16467b97STreehugger Robot
140*16467b97STreehugger Robot { Methods }
Add(const Value: T)141*16467b97STreehugger Robot function Add(const Value: T): Integer;
142*16467b97STreehugger Robot
143*16467b97STreehugger Robot procedure AddRange(const Values: array of T); overload;
144*16467b97STreehugger Robot procedure AddRange(const Collection: IEnumerable<T>); overload;
145*16467b97STreehugger Robot procedure AddRange(Collection: TEnumerable<T>); overload;
146*16467b97STreehugger Robot procedure AddRange(const List: IList<T>); overload;
147*16467b97STreehugger Robot
148*16467b97STreehugger Robot procedure Insert(Index: Integer; const Value: T);
149*16467b97STreehugger Robot
150*16467b97STreehugger Robot procedure InsertRange(Index: Integer; const Values: array of T); overload;
151*16467b97STreehugger Robot procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
152*16467b97STreehugger Robot procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;
153*16467b97STreehugger Robot procedure InsertRange(Index: Integer; const List: IList<T>); overload;
154*16467b97STreehugger Robot
Remove(const Value: T)155*16467b97STreehugger Robot function Remove(const Value: T): Integer;
156*16467b97STreehugger Robot procedure Delete(Index: Integer);
157*16467b97STreehugger Robot procedure DeleteRange(AIndex, ACount: Integer);
Extract(const Value: T)158*16467b97STreehugger Robot function Extract(const Value: T): T;
159*16467b97STreehugger Robot
160*16467b97STreehugger Robot procedure Clear;
161*16467b97STreehugger Robot
Contains(const Value: T)162*16467b97STreehugger Robot function Contains(const Value: T): Boolean;
IndexOf(const Value: T)163*16467b97STreehugger Robot function IndexOf(const Value: T): Integer;
LastIndexOf(const Value: T)164*16467b97STreehugger Robot function LastIndexOf(const Value: T): Integer;
165*16467b97STreehugger Robot
166*16467b97STreehugger Robot procedure Reverse;
167*16467b97STreehugger Robot
168*16467b97STreehugger Robot procedure Sort; overload;
169*16467b97STreehugger Robot procedure Sort(const AComparer: IComparer<T>); overload;
BinarySearch(const Item: T; out Index: Integer)170*16467b97STreehugger Robot function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;
BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>)171*16467b97STreehugger Robot function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;
172*16467b97STreehugger Robot
173*16467b97STreehugger Robot procedure TrimExcess;
GetEnumerator()174*16467b97STreehugger Robot function GetEnumerator: TList<T>.TEnumerator;
GetRange(const Index, Count: Integer)175*16467b97STreehugger Robot function GetRange(const Index, Count: Integer): IList<T>;
176*16467b97STreehugger Robot
177*16467b97STreehugger Robot { Properties }
178*16467b97STreehugger Robot
179*16467b97STreehugger Robot property Capacity: Integer read GetCapacity write SetCapacity;
180*16467b97STreehugger Robot property Count: Integer read GetCount write SetCount;
181*16467b97STreehugger Robot property Items[Index: Integer]: T read GetItem write SetItem; default;
182*16467b97STreehugger Robot property OnNotify: TCollectionNotifyEvent<T> read GetOnNotify write SetOnNotify;
183*16467b97STreehugger Robot end;
184*16467b97STreehugger Robot
185*16467b97STreehugger Robot type
186*16467b97STreehugger Robot IDictionary<TKey,TValue> = interface(IANTLRInterface)
187*16467b97STreehugger Robot ['{5937BD21-C2C8-4E30-9787-4AEFDF1072CD}']
188*16467b97STreehugger Robot { Property accessors }
GetItem(const Key: TKey)189*16467b97STreehugger Robot function GetItem(const Key: TKey): TValue;
190*16467b97STreehugger Robot procedure SetItem(const Key: TKey; const Value: TValue);
GetCount()191*16467b97STreehugger Robot function GetCount: Integer;
192*16467b97STreehugger Robot
193*16467b97STreehugger Robot { Methods }
194*16467b97STreehugger Robot procedure Add(const Key: TKey; const Value: TValue);
195*16467b97STreehugger Robot procedure Remove(const Key: TKey);
196*16467b97STreehugger Robot procedure Clear;
197*16467b97STreehugger Robot procedure TrimExcess;
TryGetValue(const Key: TKey; out Value: TValue)198*16467b97STreehugger Robot function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
199*16467b97STreehugger Robot procedure AddOrSetValue(const Key: TKey; const Value: TValue);
ContainsKey(const Key: TKey)200*16467b97STreehugger Robot function ContainsKey(const Key: TKey): Boolean;
ContainsValue(const Value: TValue)201*16467b97STreehugger Robot function ContainsValue(const Value: TValue): Boolean;
GetEnumerator()202*16467b97STreehugger Robot function GetEnumerator: TEnumerator<TPair<TKey, TValue>>;
203*16467b97STreehugger Robot
204*16467b97STreehugger Robot { Properties }
205*16467b97STreehugger Robot property Items[const Key: TKey]: TValue read GetItem write SetItem; default;
206*16467b97STreehugger Robot property Count: Integer read GetCount;
207*16467b97STreehugger Robot end;
208*16467b97STreehugger Robot
209*16467b97STreehugger Robot type
210*16467b97STreehugger Robot TList<T> = class(Generics.Collections.TList<T>, IList<T>)
211*16467b97STreehugger Robot strict private
212*16467b97STreehugger Robot FRefCount: Integer;
213*16467b97STreehugger Robot protected
214*16467b97STreehugger Robot { IInterface }
QueryInterface(const IID: TGUID; out Obj)215*16467b97STreehugger Robot function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
_AddRef()216*16467b97STreehugger Robot function _AddRef: Integer; stdcall;
_Release()217*16467b97STreehugger Robot function _Release: Integer; stdcall;
218*16467b97STreehugger Robot
219*16467b97STreehugger Robot { IList<T> }
GetCapacity()220*16467b97STreehugger Robot function GetCapacity: Integer;
221*16467b97STreehugger Robot procedure SetCapacity(Value: Integer);
GetCount()222*16467b97STreehugger Robot function GetCount: Integer;
223*16467b97STreehugger Robot procedure SetCount(Value: Integer);
GetItem(Index: Integer)224*16467b97STreehugger Robot function GetItem(Index: Integer): T;
225*16467b97STreehugger Robot procedure SetItem(Index: Integer; const Value: T);
GetOnNotify()226*16467b97STreehugger Robot function GetOnNotify: TCollectionNotifyEvent<T>;
227*16467b97STreehugger Robot procedure SetOnNotify(Value: TCollectionNotifyEvent<T>);
GetRange(const Index, Count: Integer)228*16467b97STreehugger Robot function GetRange(const Index, Count: Integer): IList<T>;
229*16467b97STreehugger Robot procedure AddRange(const List: IList<T>); overload;
230*16467b97STreehugger Robot procedure InsertRange(Index: Integer; const List: IList<T>); overload;
231*16467b97STreehugger Robot end;
232*16467b97STreehugger Robot
233*16467b97STreehugger Robot type
234*16467b97STreehugger Robot TDictionaryArray<TKey,TValue> = array of IDictionary<TKey,TValue>;
235*16467b97STreehugger Robot
236*16467b97STreehugger Robot { The TDictionary class in the first release of Delphi 2009 is very buggy.
237*16467b97STreehugger Robot This is a partial copy of that class with bug fixes. }
238*16467b97STreehugger Robot TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>, IDictionary<TKey, TValue>)
239*16467b97STreehugger Robot private
240*16467b97STreehugger Robot type
241*16467b97STreehugger Robot TItem = record
242*16467b97STreehugger Robot HashCode: Integer;
243*16467b97STreehugger Robot Key: TKey;
244*16467b97STreehugger Robot Value: TValue;
245*16467b97STreehugger Robot end;
246*16467b97STreehugger Robot TItemArray = array of TItem;
247*16467b97STreehugger Robot private
248*16467b97STreehugger Robot FItems: TItemArray;
249*16467b97STreehugger Robot FCount: Integer;
250*16467b97STreehugger Robot FComparer: IEqualityComparer<TKey>;
251*16467b97STreehugger Robot FGrowThreshold: Integer;
252*16467b97STreehugger Robot
253*16467b97STreehugger Robot procedure SetCapacity(ACapacity: Integer);
254*16467b97STreehugger Robot procedure Rehash(NewCapPow2: Integer);
255*16467b97STreehugger Robot procedure Grow;
GetBucketIndex(const Key: TKey; HashCode: Integer)256*16467b97STreehugger Robot function GetBucketIndex(const Key: TKey; HashCode: Integer): Integer;
Hash(const Key: TKey)257*16467b97STreehugger Robot function Hash(const Key: TKey): Integer;
258*16467b97STreehugger Robot procedure RehashAdd(HashCode: Integer; const Key: TKey; const Value: TValue);
259*16467b97STreehugger Robot procedure DoAdd(HashCode, Index: Integer; const Key: TKey; const Value: TValue);
260*16467b97STreehugger Robot protected
DoGetEnumerator()261*16467b97STreehugger Robot function DoGetEnumerator: TEnumerator<TPair<TKey,TValue>>; override;
262*16467b97STreehugger Robot public
263*16467b97STreehugger Robot constructor Create(ACapacity: Integer = 0); overload;
264*16467b97STreehugger Robot constructor Create(const AComparer: IEqualityComparer<TKey>); overload;
265*16467b97STreehugger Robot constructor Create(ACapacity: Integer; const AComparer: IEqualityComparer<TKey>); overload;
266*16467b97STreehugger Robot constructor Create(Collection: TEnumerable<TPair<TKey,TValue>>); overload;
267*16467b97STreehugger Robot constructor Create(Collection: TEnumerable<TPair<TKey,TValue>>; const AComparer: IEqualityComparer<TKey>); overload;
268*16467b97STreehugger Robot destructor Destroy; override;
269*16467b97STreehugger Robot
270*16467b97STreehugger Robot type
271*16467b97STreehugger Robot TPairEnumerator = class(TEnumerator<TPair<TKey,TValue>>)
272*16467b97STreehugger Robot private
273*16467b97STreehugger Robot FDictionary: TDictionary<TKey,TValue>;
274*16467b97STreehugger Robot FIndex: Integer;
GetCurrent()275*16467b97STreehugger Robot function GetCurrent: TPair<TKey,TValue>;
276*16467b97STreehugger Robot protected
DoGetCurrent()277*16467b97STreehugger Robot function DoGetCurrent: TPair<TKey,TValue>; override;
DoMoveNext()278*16467b97STreehugger Robot function DoMoveNext: Boolean; override;
279*16467b97STreehugger Robot public
280*16467b97STreehugger Robot constructor Create(ADictionary: TDictionary<TKey,TValue>);
281*16467b97STreehugger Robot property Current: TPair<TKey,TValue> read GetCurrent;
MoveNext()282*16467b97STreehugger Robot function MoveNext: Boolean;
283*16467b97STreehugger Robot end;
284*16467b97STreehugger Robot protected
285*16467b97STreehugger Robot { IInterface }
286*16467b97STreehugger Robot FRefCount: Integer;
QueryInterface(const IID: TGUID; out Obj)287*16467b97STreehugger Robot function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
_AddRef()288*16467b97STreehugger Robot function _AddRef: Integer; stdcall;
_Release()289*16467b97STreehugger Robot function _Release: Integer; stdcall;
290*16467b97STreehugger Robot protected
291*16467b97STreehugger Robot { IDictionary<TKey, TValue> }
GetItem(const Key: TKey)292*16467b97STreehugger Robot function GetItem(const Key: TKey): TValue;
293*16467b97STreehugger Robot procedure SetItem(const Key: TKey; const Value: TValue);
GetCount()294*16467b97STreehugger Robot function GetCount: Integer;
295*16467b97STreehugger Robot
296*16467b97STreehugger Robot procedure Add(const Key: TKey; const Value: TValue);
297*16467b97STreehugger Robot procedure Remove(const Key: TKey);
298*16467b97STreehugger Robot procedure Clear;
299*16467b97STreehugger Robot procedure TrimExcess;
TryGetValue(const Key: TKey; out Value: TValue)300*16467b97STreehugger Robot function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
301*16467b97STreehugger Robot procedure AddOrSetValue(const Key: TKey; const Value: TValue);
ContainsKey(const Key: TKey)302*16467b97STreehugger Robot function ContainsKey(const Key: TKey): Boolean;
ContainsValue(const Value: TValue)303*16467b97STreehugger Robot function ContainsValue(const Value: TValue): Boolean;
304*16467b97STreehugger Robot public
GetEnumerator()305*16467b97STreehugger Robot function GetEnumerator: TEnumerator<TPair<TKey, TValue>>;
306*16467b97STreehugger Robot end;
307*16467b97STreehugger Robot
308*16467b97STreehugger Robot type
309*16467b97STreehugger Robot /// <summary>
310*16467b97STreehugger Robot /// Helper for storing local variables inside a routine. The code that ANTLR
311*16467b97STreehugger Robot /// generates contains a lot of block-level variable declarations, which
312*16467b97STreehugger Robot /// the Delphi language does not support. When generating Delphi source code,
313*16467b97STreehugger Robot /// I try to detect those declarations and move them to the routine header
314*16467b97STreehugger Robot /// as much as possible. But sometimes, this is impossible.
315*16467b97STreehugger Robot /// This is a bit of an ugly (and slow) solution, but it works. Declare an
316*16467b97STreehugger Robot /// variable of the TLocalStorage type inside a routine, and you can use it
317*16467b97STreehugger Robot /// to access variables by name. For example, see the following C code:
318*16467b97STreehugger Robot /// {
319*16467b97STreehugger Robot /// int x = 3;
320*16467b97STreehugger Robot /// {
321*16467b97STreehugger Robot /// int y = x * 2;
322*16467b97STreehugger Robot /// }
323*16467b97STreehugger Robot /// }
324*16467b97STreehugger Robot /// If the Delphi code generator cannot detect the inner "y" variable, then
325*16467b97STreehugger Robot /// it uses the local storage as follows:
326*16467b97STreehugger Robot /// var
327*16467b97STreehugger Robot /// x: Integer;
328*16467b97STreehugger Robot /// Locals: TLocalStorage;
329*16467b97STreehugger Robot /// begin
330*16467b97STreehugger Robot /// Locals.Initialize;
331*16467b97STreehugger Robot /// try
332*16467b97STreehugger Robot /// x := 3;
333*16467b97STreehugger Robot /// Locals['y'] := x * 2;
334*16467b97STreehugger Robot /// finally
335*16467b97STreehugger Robot /// Locals.Finalize;
336*16467b97STreehugger Robot /// end;
337*16467b97STreehugger Robot /// end;
338*16467b97STreehugger Robot /// </summary>
339*16467b97STreehugger Robot /// <remarks>
340*16467b97STreehugger Robot /// This is a slow solution because it involves looking up variable names.
341*16467b97STreehugger Robot /// This could be done using hashing or binary search, but this is inefficient
342*16467b97STreehugger Robot /// with small collections. Since small collections are more typical in these
343*16467b97STreehugger Robot /// scenarios, we use simple linear search here.
344*16467b97STreehugger Robot /// </remarks>
345*16467b97STreehugger Robot /// <remarks>
346*16467b97STreehugger Robot /// The TLocalStorage record has space for 256 variables. For performance
347*16467b97STreehugger Robot /// reasons, this space is preallocated on the stack and does not grow if
348*16467b97STreehugger Robot /// needed. Also, no range checking is done. But 256 local variables should
349*16467b97STreehugger Robot /// be enough for all generated code.
350*16467b97STreehugger Robot /// </remarks>
351*16467b97STreehugger Robot /// <remarks>
352*16467b97STreehugger Robot /// Also note that the variable names are case sensitive, so 'x' is a
353*16467b97STreehugger Robot /// different variable than 'X'.
354*16467b97STreehugger Robot /// </remarks>
355*16467b97STreehugger Robot /// <remarks>
356*16467b97STreehugger Robot /// TLocalStorage can only store variables that are 32 bits in size, and
357*16467b97STreehugger Robot /// supports the following data typesL
358*16467b97STreehugger Robot /// -Integer
359*16467b97STreehugger Robot /// -IInterface descendants (default property)
360*16467b97STreehugger Robot /// </remarks>
361*16467b97STreehugger Robot /// <remarks>
362*16467b97STreehugger Robot /// You MUST call the Finalize method at the end of the routine to make
363*16467b97STreehugger Robot /// sure that any stored variables of type IInterface are released.
364*16467b97STreehugger Robot /// </remarks>
365*16467b97STreehugger Robot TLocalStorage = record
366*16467b97STreehugger Robot private
367*16467b97STreehugger Robot type
368*16467b97STreehugger Robot TLocalStorageEntry = record
369*16467b97STreehugger Robot FName: String;
370*16467b97STreehugger Robot FValue: Pointer;
371*16467b97STreehugger Robot FDataType: (dtInteger, dtInterface);
372*16467b97STreehugger Robot end;
373*16467b97STreehugger Robot private
374*16467b97STreehugger Robot FEntries: array [0..255] of TLocalStorageEntry;
375*16467b97STreehugger Robot FCount: Integer;
GetAsInteger(const Name: String)376*16467b97STreehugger Robot function GetAsInteger(const Name: String): Integer;
377*16467b97STreehugger Robot procedure SetAsInteger(const Name: String; const Value: Integer);
GetAsInterface(const Name: String)378*16467b97STreehugger Robot function GetAsInterface(const Name: String): IInterface;
379*16467b97STreehugger Robot procedure SetAsInterface(const Name: String; const Value: IInterface);
380*16467b97STreehugger Robot public
381*16467b97STreehugger Robot procedure Initialize;
382*16467b97STreehugger Robot procedure Finalize;
383*16467b97STreehugger Robot
384*16467b97STreehugger Robot property Count: Integer read FCount;
385*16467b97STreehugger Robot property AsInteger[const Name: String]: Integer read GetAsInteger write SetAsInteger;
386*16467b97STreehugger Robot property AsInterface[const Name: String]: IInterface read GetAsInterface write SetAsInterface; default;
387*16467b97STreehugger Robot end;
388*16467b97STreehugger Robot
InCircularRange(Bottom, Item, TopInc: Integer)389*16467b97STreehugger Robot function InCircularRange(Bottom, Item, TopInc: Integer): Boolean;
390*16467b97STreehugger Robot
391*16467b97STreehugger Robot { Checks if A and B are implemented by the same object }
SameObj(const A, B: IInterface)392*16467b97STreehugger Robot function SameObj(const A, B: IInterface): Boolean;
393*16467b97STreehugger Robot
IfThen(const AValue: Boolean; const ATrue: IANTLRInterface; const AFalse: IANTLRInterface = nil)394*16467b97STreehugger Robot function IfThen(const AValue: Boolean; const ATrue: IANTLRInterface; const AFalse: IANTLRInterface = nil): IANTLRInterface; overload;
395*16467b97STreehugger Robot
IsUpper(const C: Char)396*16467b97STreehugger Robot function IsUpper(const C: Char): Boolean;
397*16467b97STreehugger Robot
398*16467b97STreehugger Robot implementation
399*16467b97STreehugger Robot
400*16467b97STreehugger Robot uses
401*16467b97STreehugger Robot Windows,
402*16467b97STreehugger Robot SysUtils;
403*16467b97STreehugger Robot
SameObj(const A, B: IInterface)404*16467b97STreehugger Robot function SameObj(const A, B: IInterface): Boolean;
405*16467b97STreehugger Robot var
406*16467b97STreehugger Robot X, Y: IInterface;
407*16467b97STreehugger Robot begin
408*16467b97STreehugger Robot if (A = nil) or (B = nil) then
409*16467b97STreehugger Robot Result := (A = B)
410*16467b97STreehugger Robot else if (A.QueryInterface(IInterface, X) = S_OK)
411*16467b97STreehugger Robot and (B.QueryInterface(IInterface, Y) = S_OK)
412*16467b97STreehugger Robot then
413*16467b97STreehugger Robot Result := (X = Y)
414*16467b97STreehugger Robot else
415*16467b97STreehugger Robot Result := (A = B);
416*16467b97STreehugger Robot end;
417*16467b97STreehugger Robot
IfThen(const AValue: Boolean; const ATrue: IANTLRInterface; const AFalse: IANTLRInterface = nil)418*16467b97STreehugger Robot function IfThen(const AValue: Boolean; const ATrue: IANTLRInterface; const AFalse: IANTLRInterface = nil): IANTLRInterface; overload;
419*16467b97STreehugger Robot begin
420*16467b97STreehugger Robot if AValue then
421*16467b97STreehugger Robot Result := ATrue
422*16467b97STreehugger Robot else
423*16467b97STreehugger Robot Result := AFalse;
424*16467b97STreehugger Robot end;
425*16467b97STreehugger Robot
IsUpper(const C: Char)426*16467b97STreehugger Robot function IsUpper(const C: Char): Boolean;
427*16467b97STreehugger Robot begin
428*16467b97STreehugger Robot Result := (C >= 'A') and (C <= 'Z');
429*16467b97STreehugger Robot
430*16467b97STreehugger Robot end;
431*16467b97STreehugger Robot { TANTLRObject }
432*16467b97STreehugger Robot
GetImplementornull433*16467b97STreehugger Robot function TANTLRObject.GetImplementor: TObject;
434*16467b97STreehugger Robot begin
435*16467b97STreehugger Robot Result := Self;
436*16467b97STreehugger Robot end;
437*16467b97STreehugger Robot
438*16467b97STreehugger Robot { TANTLRString }
439*16467b97STreehugger Robot
440*16467b97STreehugger Robot constructor TANTLRString.Create(const AValue: String);
441*16467b97STreehugger Robot begin
442*16467b97STreehugger Robot inherited Create;
443*16467b97STreehugger Robot FValue := AValue;
444*16467b97STreehugger Robot end;
445*16467b97STreehugger Robot
TANTLRString.GetValue()446*16467b97STreehugger Robot function TANTLRString.GetValue: String;
447*16467b97STreehugger Robot begin
448*16467b97STreehugger Robot Result := FValue;
449*16467b97STreehugger Robot end;
450*16467b97STreehugger Robot
451*16467b97STreehugger Robot procedure TANTLRString.SetValue(const Value: String);
452*16467b97STreehugger Robot begin
453*16467b97STreehugger Robot FValue := Value;
454*16467b97STreehugger Robot end;
455*16467b97STreehugger Robot
ToStringnull456*16467b97STreehugger Robot function TANTLRString.ToString: String;
457*16467b97STreehugger Robot begin
458*16467b97STreehugger Robot Result := FValue;
459*16467b97STreehugger Robot end;
460*16467b97STreehugger Robot
461*16467b97STreehugger Robot { TList<T> }
462*16467b97STreehugger Robot
463*16467b97STreehugger Robot procedure TList<T>.AddRange(const List: IList<T>);
464*16467b97STreehugger Robot begin
465*16467b97STreehugger Robot InsertRange(GetCount, List);
466*16467b97STreehugger Robot end;
467*16467b97STreehugger Robot
TList()468*16467b97STreehugger Robot function TList<T>.GetCapacity: Integer;
469*16467b97STreehugger Robot begin
470*16467b97STreehugger Robot Result := inherited Capacity;
471*16467b97STreehugger Robot end;
472*16467b97STreehugger Robot
TList()473*16467b97STreehugger Robot function TList<T>.GetCount: Integer;
474*16467b97STreehugger Robot begin
475*16467b97STreehugger Robot Result := inherited Count;
476*16467b97STreehugger Robot end;
477*16467b97STreehugger Robot
GetItemnull478*16467b97STreehugger Robot function TList<T>.GetItem(Index: Integer): T;
479*16467b97STreehugger Robot begin
480*16467b97STreehugger Robot Result := inherited Items[Index];
481*16467b97STreehugger Robot end;
482*16467b97STreehugger Robot
TList()483*16467b97STreehugger Robot function TList<T>.GetOnNotify: TCollectionNotifyEvent<T>;
484*16467b97STreehugger Robot begin
485*16467b97STreehugger Robot Result := inherited OnNotify;
486*16467b97STreehugger Robot end;
487*16467b97STreehugger Robot
TList(const Index, Count: Integer)488*16467b97STreehugger Robot function TList<T>.GetRange(const Index, Count: Integer): IList<T>;
489*16467b97STreehugger Robot var
490*16467b97STreehugger Robot I: Integer;
491*16467b97STreehugger Robot begin
492*16467b97STreehugger Robot Result := TList<T>.Create;
493*16467b97STreehugger Robot Result.Capacity := Count;
494*16467b97STreehugger Robot for I := Index to Index + Count - 1 do
495*16467b97STreehugger Robot Result.Add(GetItem(I));
496*16467b97STreehugger Robot end;
497*16467b97STreehugger Robot
498*16467b97STreehugger Robot procedure TList<T>.InsertRange(Index: Integer; const List: IList<T>);
499*16467b97STreehugger Robot var
500*16467b97STreehugger Robot Item: T;
501*16467b97STreehugger Robot begin
502*16467b97STreehugger Robot for Item in List do
503*16467b97STreehugger Robot begin
504*16467b97STreehugger Robot Insert(Index, Item);
505*16467b97STreehugger Robot Inc(Index);
506*16467b97STreehugger Robot end;
507*16467b97STreehugger Robot end;
508*16467b97STreehugger Robot
TList(const IID: TGUID; out Obj)509*16467b97STreehugger Robot function TList<T>.QueryInterface(const IID: TGUID; out Obj): HResult;
510*16467b97STreehugger Robot begin
511*16467b97STreehugger Robot if GetInterface(IID, Obj) then
512*16467b97STreehugger Robot Result := 0
513*16467b97STreehugger Robot else
514*16467b97STreehugger Robot Result := E_NOINTERFACE;
515*16467b97STreehugger Robot end;
516*16467b97STreehugger Robot
517*16467b97STreehugger Robot procedure TList<T>.SetCapacity(Value: Integer);
518*16467b97STreehugger Robot begin
519*16467b97STreehugger Robot inherited Capacity := Value;
520*16467b97STreehugger Robot end;
521*16467b97STreehugger Robot
522*16467b97STreehugger Robot procedure TList<T>.SetCount(Value: Integer);
523*16467b97STreehugger Robot begin
524*16467b97STreehugger Robot inherited Count := Value;
525*16467b97STreehugger Robot end;
526*16467b97STreehugger Robot
527*16467b97STreehugger Robot procedure TList<T>.SetItem(Index: Integer; const Value: T);
528*16467b97STreehugger Robot begin
529*16467b97STreehugger Robot inherited Items[Index] := Value;
530*16467b97STreehugger Robot end;
531*16467b97STreehugger Robot
532*16467b97STreehugger Robot procedure TList<T>.SetOnNotify(Value: TCollectionNotifyEvent<T>);
533*16467b97STreehugger Robot begin
534*16467b97STreehugger Robot inherited OnNotify := Value;
535*16467b97STreehugger Robot end;
536*16467b97STreehugger Robot
TList()537*16467b97STreehugger Robot function TList<T>._AddRef: Integer;
538*16467b97STreehugger Robot begin
539*16467b97STreehugger Robot Result := InterlockedIncrement(FRefCount);
540*16467b97STreehugger Robot end;
541*16467b97STreehugger Robot
_Releasenull542*16467b97STreehugger Robot function TList<T>._Release: Integer;
543*16467b97STreehugger Robot begin
544*16467b97STreehugger Robot Result := InterlockedDecrement(FRefCount);
545*16467b97STreehugger Robot if (Result = 0) then
546*16467b97STreehugger Robot Destroy;
547*16467b97STreehugger Robot end;
548*16467b97STreehugger Robot
549*16467b97STreehugger Robot { TDictionary<TKey, TValue> }
550*16467b97STreehugger Robot
551*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.Rehash(NewCapPow2: Integer);
552*16467b97STreehugger Robot var
553*16467b97STreehugger Robot oldItems, newItems: TItemArray;
554*16467b97STreehugger Robot i: Integer;
555*16467b97STreehugger Robot begin
556*16467b97STreehugger Robot if NewCapPow2 = Length(FItems) then
557*16467b97STreehugger Robot Exit
558*16467b97STreehugger Robot else if NewCapPow2 < 0 then
559*16467b97STreehugger Robot OutOfMemoryError;
560*16467b97STreehugger Robot
561*16467b97STreehugger Robot oldItems := FItems;
562*16467b97STreehugger Robot SetLength(newItems, NewCapPow2);
563*16467b97STreehugger Robot FItems := newItems;
564*16467b97STreehugger Robot FGrowThreshold := NewCapPow2 shr 1 + NewCapPow2 shr 2;
565*16467b97STreehugger Robot
566*16467b97STreehugger Robot for i := 0 to Length(oldItems) - 1 do
567*16467b97STreehugger Robot if oldItems[i].HashCode <> 0 then
568*16467b97STreehugger Robot RehashAdd(oldItems[i].HashCode, oldItems[i].Key, oldItems[i].Value);
569*16467b97STreehugger Robot end;
570*16467b97STreehugger Robot
571*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.SetCapacity(ACapacity: Integer);
572*16467b97STreehugger Robot var
573*16467b97STreehugger Robot newCap: Integer;
574*16467b97STreehugger Robot begin
575*16467b97STreehugger Robot if ACapacity < FCount then
576*16467b97STreehugger Robot raise EArgumentOutOfRangeException.CreateRes(@sArgumentOutOfRange);
577*16467b97STreehugger Robot
578*16467b97STreehugger Robot if ACapacity = 0 then
579*16467b97STreehugger Robot Rehash(0)
580*16467b97STreehugger Robot else
581*16467b97STreehugger Robot begin
582*16467b97STreehugger Robot newCap := 4;
583*16467b97STreehugger Robot while newCap < ACapacity do
584*16467b97STreehugger Robot newCap := newCap shl 1;
585*16467b97STreehugger Robot Rehash(newCap);
586*16467b97STreehugger Robot end
587*16467b97STreehugger Robot end;
588*16467b97STreehugger Robot
589*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.Grow;
590*16467b97STreehugger Robot var
591*16467b97STreehugger Robot newCap: Integer;
592*16467b97STreehugger Robot begin
593*16467b97STreehugger Robot newCap := Length(FItems) * 2;
594*16467b97STreehugger Robot if newCap = 0 then
595*16467b97STreehugger Robot newCap := 4;
596*16467b97STreehugger Robot Rehash(newCap);
597*16467b97STreehugger Robot end;
598*16467b97STreehugger Robot
TDictionary(const Key: TKey; HashCode: Integer)599*16467b97STreehugger Robot function TDictionary<TKey,TValue>.GetBucketIndex(const Key: TKey; HashCode: Integer): Integer;
600*16467b97STreehugger Robot var
601*16467b97STreehugger Robot start, hc: Integer;
602*16467b97STreehugger Robot begin
603*16467b97STreehugger Robot if Length(FItems) = 0 then
604*16467b97STreehugger Robot Exit(not High(Integer));
605*16467b97STreehugger Robot
606*16467b97STreehugger Robot start := HashCode and (Length(FItems) - 1);
607*16467b97STreehugger Robot Result := start;
608*16467b97STreehugger Robot while True do
609*16467b97STreehugger Robot begin
610*16467b97STreehugger Robot hc := FItems[Result].HashCode;
611*16467b97STreehugger Robot
612*16467b97STreehugger Robot // Not found: return complement of insertion point.
613*16467b97STreehugger Robot if hc = 0 then
614*16467b97STreehugger Robot Exit(not Result);
615*16467b97STreehugger Robot
616*16467b97STreehugger Robot // Found: return location.
617*16467b97STreehugger Robot if (hc = HashCode) and FComparer.Equals(FItems[Result].Key, Key) then
618*16467b97STreehugger Robot Exit(Result);
619*16467b97STreehugger Robot
620*16467b97STreehugger Robot Inc(Result);
621*16467b97STreehugger Robot if Result >= Length(FItems) then
622*16467b97STreehugger Robot Result := 0;
623*16467b97STreehugger Robot end;
624*16467b97STreehugger Robot end;
625*16467b97STreehugger Robot
GetCountnull626*16467b97STreehugger Robot function TDictionary<TKey, TValue>.GetCount: Integer;
627*16467b97STreehugger Robot begin
628*16467b97STreehugger Robot Result := FCount;
629*16467b97STreehugger Robot end;
630*16467b97STreehugger Robot
TDictionary(const Key: TKey)631*16467b97STreehugger Robot function TDictionary<TKey,TValue>.Hash(const Key: TKey): Integer;
632*16467b97STreehugger Robot const
633*16467b97STreehugger Robot PositiveMask = not Integer($80000000);
634*16467b97STreehugger Robot begin
635*16467b97STreehugger Robot // Double-Abs to avoid -MaxInt and MinInt problems.
636*16467b97STreehugger Robot // Not using compiler-Abs because we *must* get a positive integer;
637*16467b97STreehugger Robot // for compiler, Abs(Low(Integer)) is a null op.
638*16467b97STreehugger Robot Result := PositiveMask and ((PositiveMask and FComparer.GetHashCode(Key)) + 1);
639*16467b97STreehugger Robot end;
640*16467b97STreehugger Robot
GetItemnull641*16467b97STreehugger Robot function TDictionary<TKey,TValue>.GetItem(const Key: TKey): TValue;
642*16467b97STreehugger Robot var
643*16467b97STreehugger Robot index: Integer;
644*16467b97STreehugger Robot begin
645*16467b97STreehugger Robot index := GetBucketIndex(Key, Hash(Key));
646*16467b97STreehugger Robot if index < 0 then
647*16467b97STreehugger Robot raise EListError.CreateRes(@sGenericItemNotFound);
648*16467b97STreehugger Robot Result := FItems[index].Value;
649*16467b97STreehugger Robot end;
650*16467b97STreehugger Robot
651*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.SetItem(const Key: TKey; const Value: TValue);
652*16467b97STreehugger Robot var
653*16467b97STreehugger Robot index: Integer;
654*16467b97STreehugger Robot oldValue: TValue;
655*16467b97STreehugger Robot begin
656*16467b97STreehugger Robot index := GetBucketIndex(Key, Hash(Key));
657*16467b97STreehugger Robot if index < 0 then
658*16467b97STreehugger Robot raise EListError.CreateRes(@sGenericItemNotFound);
659*16467b97STreehugger Robot
660*16467b97STreehugger Robot oldValue := FItems[index].Value;
661*16467b97STreehugger Robot FItems[index].Value := Value;
662*16467b97STreehugger Robot end;
663*16467b97STreehugger Robot
664*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.RehashAdd(HashCode: Integer; const Key: TKey; const Value: TValue);
665*16467b97STreehugger Robot var
666*16467b97STreehugger Robot index: Integer;
667*16467b97STreehugger Robot begin
668*16467b97STreehugger Robot index := not GetBucketIndex(Key, HashCode);
669*16467b97STreehugger Robot FItems[index].HashCode := HashCode;
670*16467b97STreehugger Robot FItems[index].Key := Key;
671*16467b97STreehugger Robot FItems[index].Value := Value;
672*16467b97STreehugger Robot end;
673*16467b97STreehugger Robot
QueryInterfacenull674*16467b97STreehugger Robot function TDictionary<TKey, TValue>.QueryInterface(const IID: TGUID;
675*16467b97STreehugger Robot out Obj): HResult;
676*16467b97STreehugger Robot begin
677*16467b97STreehugger Robot if GetInterface(IID, Obj) then
678*16467b97STreehugger Robot Result := 0
679*16467b97STreehugger Robot else
680*16467b97STreehugger Robot Result := E_NOINTERFACE;
681*16467b97STreehugger Robot end;
682*16467b97STreehugger Robot
_AddRefnull683*16467b97STreehugger Robot function TDictionary<TKey, TValue>._AddRef: Integer;
684*16467b97STreehugger Robot begin
685*16467b97STreehugger Robot Result := InterlockedIncrement(FRefCount);
686*16467b97STreehugger Robot end;
687*16467b97STreehugger Robot
_Releasenull688*16467b97STreehugger Robot function TDictionary<TKey, TValue>._Release: Integer;
689*16467b97STreehugger Robot begin
690*16467b97STreehugger Robot Result := InterlockedDecrement(FRefCount);
691*16467b97STreehugger Robot if (Result = 0) then
692*16467b97STreehugger Robot Destroy;
693*16467b97STreehugger Robot end;
694*16467b97STreehugger Robot
695*16467b97STreehugger Robot constructor TDictionary<TKey,TValue>.Create(ACapacity: Integer = 0);
696*16467b97STreehugger Robot begin
697*16467b97STreehugger Robot Create(ACapacity, nil);
698*16467b97STreehugger Robot end;
699*16467b97STreehugger Robot
700*16467b97STreehugger Robot constructor TDictionary<TKey,TValue>.Create(const AComparer: IEqualityComparer<TKey>);
701*16467b97STreehugger Robot begin
702*16467b97STreehugger Robot Create(0, AComparer);
703*16467b97STreehugger Robot end;
704*16467b97STreehugger Robot
705*16467b97STreehugger Robot constructor TDictionary<TKey,TValue>.Create(ACapacity: Integer; const AComparer: IEqualityComparer<TKey>);
706*16467b97STreehugger Robot var
707*16467b97STreehugger Robot cap: Integer;
708*16467b97STreehugger Robot begin
709*16467b97STreehugger Robot inherited Create;
710*16467b97STreehugger Robot if ACapacity < 0 then
711*16467b97STreehugger Robot raise EArgumentOutOfRangeException.CreateRes(@sArgumentOutOfRange);
712*16467b97STreehugger Robot FComparer := AComparer;
713*16467b97STreehugger Robot if FComparer = nil then
714*16467b97STreehugger Robot FComparer := TEqualityComparer<TKey>.Default;
715*16467b97STreehugger Robot SetCapacity(ACapacity);
716*16467b97STreehugger Robot end;
717*16467b97STreehugger Robot
718*16467b97STreehugger Robot constructor TDictionary<TKey, TValue>.Create(
719*16467b97STreehugger Robot Collection: TEnumerable<TPair<TKey, TValue>>);
720*16467b97STreehugger Robot var
721*16467b97STreehugger Robot item: TPair<TKey,TValue>;
722*16467b97STreehugger Robot begin
723*16467b97STreehugger Robot Create(0, nil);
724*16467b97STreehugger Robot for item in Collection do
725*16467b97STreehugger Robot AddOrSetValue(item.Key, item.Value);
726*16467b97STreehugger Robot end;
727*16467b97STreehugger Robot
728*16467b97STreehugger Robot constructor TDictionary<TKey, TValue>.Create(
729*16467b97STreehugger Robot Collection: TEnumerable<TPair<TKey, TValue>>;
730*16467b97STreehugger Robot const AComparer: IEqualityComparer<TKey>);
731*16467b97STreehugger Robot var
732*16467b97STreehugger Robot item: TPair<TKey,TValue>;
733*16467b97STreehugger Robot begin
734*16467b97STreehugger Robot Create(0, AComparer);
735*16467b97STreehugger Robot for item in Collection do
736*16467b97STreehugger Robot AddOrSetValue(item.Key, item.Value);
737*16467b97STreehugger Robot end;
738*16467b97STreehugger Robot
739*16467b97STreehugger Robot destructor TDictionary<TKey,TValue>.Destroy;
740*16467b97STreehugger Robot begin
741*16467b97STreehugger Robot Clear;
742*16467b97STreehugger Robot inherited;
743*16467b97STreehugger Robot end;
744*16467b97STreehugger Robot
745*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.Add(const Key: TKey; const Value: TValue);
746*16467b97STreehugger Robot var
747*16467b97STreehugger Robot index, hc: Integer;
748*16467b97STreehugger Robot begin
749*16467b97STreehugger Robot if FCount >= FGrowThreshold then
750*16467b97STreehugger Robot Grow;
751*16467b97STreehugger Robot
752*16467b97STreehugger Robot hc := Hash(Key);
753*16467b97STreehugger Robot index := GetBucketIndex(Key, hc);
754*16467b97STreehugger Robot if index >= 0 then
755*16467b97STreehugger Robot raise EListError.CreateRes(@sGenericDuplicateItem);
756*16467b97STreehugger Robot
757*16467b97STreehugger Robot DoAdd(hc, not index, Key, Value);
758*16467b97STreehugger Robot end;
759*16467b97STreehugger Robot
InCircularRange(Bottom, Item, TopInc: Integer)760*16467b97STreehugger Robot function InCircularRange(Bottom, Item, TopInc: Integer): Boolean;
761*16467b97STreehugger Robot begin
762*16467b97STreehugger Robot Result := (Bottom < Item) and (Item <= TopInc) // normal
763*16467b97STreehugger Robot or (TopInc < Bottom) and (Item > Bottom) // top wrapped
764*16467b97STreehugger Robot or (TopInc < Bottom) and (Item <= TopInc) // top and item wrapped
765*16467b97STreehugger Robot end;
766*16467b97STreehugger Robot
767*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.Remove(const Key: TKey);
768*16467b97STreehugger Robot var
769*16467b97STreehugger Robot gap, index, hc, bucket: Integer;
770*16467b97STreehugger Robot oldValue: TValue;
771*16467b97STreehugger Robot begin
772*16467b97STreehugger Robot hc := Hash(Key);
773*16467b97STreehugger Robot index := GetBucketIndex(Key, hc);
774*16467b97STreehugger Robot if index < 0 then
775*16467b97STreehugger Robot Exit;
776*16467b97STreehugger Robot
777*16467b97STreehugger Robot // Removing item from linear probe hash table is moderately
778*16467b97STreehugger Robot // tricky. We need to fill in gaps, which will involve moving items
779*16467b97STreehugger Robot // which may not even hash to the same location.
780*16467b97STreehugger Robot // Knuth covers it well enough in Vol III. 6.4.; but beware, Algorithm R
781*16467b97STreehugger Robot // (2nd ed) has a bug: step R4 should go to step R1, not R2 (already errata'd).
782*16467b97STreehugger Robot // My version does linear probing forward, not backward, however.
783*16467b97STreehugger Robot
784*16467b97STreehugger Robot // gap refers to the hole that needs filling-in by shifting items down.
785*16467b97STreehugger Robot // index searches for items that have been probed out of their slot,
786*16467b97STreehugger Robot // but being careful not to move items if their bucket is between
787*16467b97STreehugger Robot // our gap and our index (so that they'd be moved before their bucket).
788*16467b97STreehugger Robot // We move the item at index into the gap, whereupon the new gap is
789*16467b97STreehugger Robot // at the index. If the index hits a hole, then we're done.
790*16467b97STreehugger Robot
791*16467b97STreehugger Robot // If our load factor was exactly 1, we'll need to hit this hole
792*16467b97STreehugger Robot // in order to terminate. Shouldn't normally be necessary, though.
793*16467b97STreehugger Robot FItems[index].HashCode := 0;
794*16467b97STreehugger Robot
795*16467b97STreehugger Robot gap := index;
796*16467b97STreehugger Robot while True do
797*16467b97STreehugger Robot begin
798*16467b97STreehugger Robot Inc(index);
799*16467b97STreehugger Robot if index = Length(FItems) then
800*16467b97STreehugger Robot index := 0;
801*16467b97STreehugger Robot
802*16467b97STreehugger Robot hc := FItems[index].HashCode;
803*16467b97STreehugger Robot if hc = 0 then
804*16467b97STreehugger Robot Break;
805*16467b97STreehugger Robot
806*16467b97STreehugger Robot bucket := hc and (Length(FItems) - 1);
807*16467b97STreehugger Robot if not InCircularRange(gap, bucket, index) then
808*16467b97STreehugger Robot begin
809*16467b97STreehugger Robot FItems[gap] := FItems[index];
810*16467b97STreehugger Robot gap := index;
811*16467b97STreehugger Robot // The gap moved, but we still need to find it to terminate.
812*16467b97STreehugger Robot FItems[gap].HashCode := 0;
813*16467b97STreehugger Robot end;
814*16467b97STreehugger Robot end;
815*16467b97STreehugger Robot
816*16467b97STreehugger Robot FItems[gap].HashCode := 0;
817*16467b97STreehugger Robot FItems[gap].Key := Default(TKey);
818*16467b97STreehugger Robot oldValue := FItems[gap].Value;
819*16467b97STreehugger Robot FItems[gap].Value := Default(TValue);
820*16467b97STreehugger Robot Dec(FCount);
821*16467b97STreehugger Robot end;
822*16467b97STreehugger Robot
823*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.Clear;
824*16467b97STreehugger Robot begin
825*16467b97STreehugger Robot FCount := 0;
826*16467b97STreehugger Robot FGrowThreshold := 0;
827*16467b97STreehugger Robot SetLength(FItems, 0);
828*16467b97STreehugger Robot SetCapacity(0);
829*16467b97STreehugger Robot end;
830*16467b97STreehugger Robot
831*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.TrimExcess;
832*16467b97STreehugger Robot begin
833*16467b97STreehugger Robot SetCapacity(FCount);
834*16467b97STreehugger Robot end;
835*16467b97STreehugger Robot
TryGetValuenull836*16467b97STreehugger Robot function TDictionary<TKey,TValue>.TryGetValue(const Key: TKey; out Value: TValue): Boolean;
837*16467b97STreehugger Robot var
838*16467b97STreehugger Robot index: Integer;
839*16467b97STreehugger Robot begin
840*16467b97STreehugger Robot index := GetBucketIndex(Key, Hash(Key));
841*16467b97STreehugger Robot Result := index >= 0;
842*16467b97STreehugger Robot if Result then
843*16467b97STreehugger Robot Value := FItems[index].Value
844*16467b97STreehugger Robot else
845*16467b97STreehugger Robot Value := Default(TValue);
846*16467b97STreehugger Robot end;
847*16467b97STreehugger Robot
848*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.DoAdd(HashCode, Index: Integer; const Key: TKey; const Value: TValue);
849*16467b97STreehugger Robot begin
850*16467b97STreehugger Robot FItems[Index].HashCode := HashCode;
851*16467b97STreehugger Robot FItems[Index].Key := Key;
852*16467b97STreehugger Robot FItems[Index].Value := Value;
853*16467b97STreehugger Robot Inc(FCount);
854*16467b97STreehugger Robot end;
855*16467b97STreehugger Robot
TDictionary()856*16467b97STreehugger Robot function TDictionary<TKey, TValue>.DoGetEnumerator: TEnumerator<TPair<TKey, TValue>>;
857*16467b97STreehugger Robot begin
858*16467b97STreehugger Robot Result := GetEnumerator;
859*16467b97STreehugger Robot end;
860*16467b97STreehugger Robot
861*16467b97STreehugger Robot procedure TDictionary<TKey,TValue>.AddOrSetValue(const Key: TKey; const Value: TValue);
862*16467b97STreehugger Robot begin
863*16467b97STreehugger Robot if ContainsKey(Key) then
864*16467b97STreehugger Robot SetItem(Key,Value)
865*16467b97STreehugger Robot else
866*16467b97STreehugger Robot Add(Key,Value);
867*16467b97STreehugger Robot end;
868*16467b97STreehugger Robot
TDictionary(const Key: TKey)869*16467b97STreehugger Robot function TDictionary<TKey,TValue>.ContainsKey(const Key: TKey): Boolean;
870*16467b97STreehugger Robot begin
871*16467b97STreehugger Robot Result := GetBucketIndex(Key, Hash(Key)) >= 0;
872*16467b97STreehugger Robot end;
873*16467b97STreehugger Robot
ContainsValuenull874*16467b97STreehugger Robot function TDictionary<TKey,TValue>.ContainsValue(const Value: TValue): Boolean;
875*16467b97STreehugger Robot var
876*16467b97STreehugger Robot i: Integer;
877*16467b97STreehugger Robot c: IEqualityComparer<TValue>;
878*16467b97STreehugger Robot begin
879*16467b97STreehugger Robot c := TEqualityComparer<TValue>.Default;
880*16467b97STreehugger Robot
881*16467b97STreehugger Robot for i := 0 to Length(FItems) - 1 do
882*16467b97STreehugger Robot if (FItems[i].HashCode <> 0) and c.Equals(FItems[i].Value, Value) then
883*16467b97STreehugger Robot Exit(True);
884*16467b97STreehugger Robot Result := False;
885*16467b97STreehugger Robot end;
886*16467b97STreehugger Robot
GetEnumeratornull887*16467b97STreehugger Robot function TDictionary<TKey,TValue>.GetEnumerator: TPairEnumerator;
888*16467b97STreehugger Robot begin
889*16467b97STreehugger Robot Result := TPairEnumerator.Create(Self);
890*16467b97STreehugger Robot end;
891*16467b97STreehugger Robot
892*16467b97STreehugger Robot // Pairs
893*16467b97STreehugger Robot
894*16467b97STreehugger Robot constructor TDictionary<TKey,TValue>.TPairEnumerator.Create(ADictionary: TDictionary<TKey,TValue>);
895*16467b97STreehugger Robot begin
896*16467b97STreehugger Robot inherited Create;
897*16467b97STreehugger Robot FIndex := -1;
898*16467b97STreehugger Robot FDictionary := ADictionary;
899*16467b97STreehugger Robot end;
900*16467b97STreehugger Robot
TPairEnumeratornull901*16467b97STreehugger Robot function TDictionary<TKey, TValue>.TPairEnumerator.DoGetCurrent: TPair<TKey, TValue>;
902*16467b97STreehugger Robot begin
903*16467b97STreehugger Robot Result := GetCurrent;
904*16467b97STreehugger Robot end;
905*16467b97STreehugger Robot
TPairEnumeratornull906*16467b97STreehugger Robot function TDictionary<TKey, TValue>.TPairEnumerator.DoMoveNext: Boolean;
907*16467b97STreehugger Robot begin
908*16467b97STreehugger Robot Result := MoveNext;
909*16467b97STreehugger Robot end;
910*16467b97STreehugger Robot
TPairEnumeratornull911*16467b97STreehugger Robot function TDictionary<TKey,TValue>.TPairEnumerator.GetCurrent: TPair<TKey,TValue>;
912*16467b97STreehugger Robot begin
913*16467b97STreehugger Robot Result.Key := FDictionary.FItems[FIndex].Key;
914*16467b97STreehugger Robot Result.Value := FDictionary.FItems[FIndex].Value;
915*16467b97STreehugger Robot end;
916*16467b97STreehugger Robot
TPairEnumeratornull917*16467b97STreehugger Robot function TDictionary<TKey,TValue>.TPairEnumerator.MoveNext: Boolean;
918*16467b97STreehugger Robot begin
919*16467b97STreehugger Robot while FIndex < Length(FDictionary.FItems) - 1 do
920*16467b97STreehugger Robot begin
921*16467b97STreehugger Robot Inc(FIndex);
922*16467b97STreehugger Robot if FDictionary.FItems[FIndex].HashCode <> 0 then
923*16467b97STreehugger Robot Exit(True);
924*16467b97STreehugger Robot end;
925*16467b97STreehugger Robot Result := False;
926*16467b97STreehugger Robot end;
927*16467b97STreehugger Robot
928*16467b97STreehugger Robot { TLocalStorage }
929*16467b97STreehugger Robot
930*16467b97STreehugger Robot procedure TLocalStorage.Finalize;
931*16467b97STreehugger Robot var
932*16467b97STreehugger Robot I: Integer;
933*16467b97STreehugger Robot begin
934*16467b97STreehugger Robot for I := 0 to FCount - 1 do
935*16467b97STreehugger Robot if (FEntries[I].FDataType = dtInterface) then
936*16467b97STreehugger Robot IInterface(FEntries[I].FValue) := nil;
937*16467b97STreehugger Robot end;
938*16467b97STreehugger Robot
GetAsIntegernull939*16467b97STreehugger Robot function TLocalStorage.GetAsInteger(const Name: String): Integer;
940*16467b97STreehugger Robot var
941*16467b97STreehugger Robot I: Integer;
942*16467b97STreehugger Robot begin
943*16467b97STreehugger Robot for I := 0 to FCount - 1 do
944*16467b97STreehugger Robot if (FEntries[I].FName = Name) then
945*16467b97STreehugger Robot Exit(Integer(FEntries[I].FValue));
946*16467b97STreehugger Robot Result := 0;
947*16467b97STreehugger Robot end;
948*16467b97STreehugger Robot
TLocalStorage.GetAsInterface(const Name: String)949*16467b97STreehugger Robot function TLocalStorage.GetAsInterface(const Name: String): IInterface;
950*16467b97STreehugger Robot var
951*16467b97STreehugger Robot I: Integer;
952*16467b97STreehugger Robot begin
953*16467b97STreehugger Robot for I := 0 to FCount - 1 do
954*16467b97STreehugger Robot if (FEntries[I].FName = Name) then
955*16467b97STreehugger Robot Exit(IInterface(FEntries[I].FValue));
956*16467b97STreehugger Robot Result := nil;
957*16467b97STreehugger Robot end;
958*16467b97STreehugger Robot
959*16467b97STreehugger Robot procedure TLocalStorage.Initialize;
960*16467b97STreehugger Robot begin
961*16467b97STreehugger Robot FCount := 0;
962*16467b97STreehugger Robot end;
963*16467b97STreehugger Robot
964*16467b97STreehugger Robot procedure TLocalStorage.SetAsInteger(const Name: String; const Value: Integer);
965*16467b97STreehugger Robot var
966*16467b97STreehugger Robot I: Integer;
967*16467b97STreehugger Robot begin
968*16467b97STreehugger Robot for I := 0 to FCount - 1 do
969*16467b97STreehugger Robot if (FEntries[I].FName = Name) then
970*16467b97STreehugger Robot begin
971*16467b97STreehugger Robot FEntries[I].FValue := Pointer(Value);
972*16467b97STreehugger Robot Exit;
973*16467b97STreehugger Robot end;
974*16467b97STreehugger Robot FEntries[FCount].FName := Name;
975*16467b97STreehugger Robot FEntries[FCount].FValue := Pointer(Value);
976*16467b97STreehugger Robot FEntries[FCount].FDataType := dtInteger;
977*16467b97STreehugger Robot Inc(FCount);
978*16467b97STreehugger Robot end;
979*16467b97STreehugger Robot
980*16467b97STreehugger Robot procedure TLocalStorage.SetAsInterface(const Name: String;
981*16467b97STreehugger Robot const Value: IInterface);
982*16467b97STreehugger Robot var
983*16467b97STreehugger Robot I: Integer;
984*16467b97STreehugger Robot begin
985*16467b97STreehugger Robot for I := 0 to FCount - 1 do
986*16467b97STreehugger Robot if (FEntries[I].FName = Name) then
987*16467b97STreehugger Robot begin
988*16467b97STreehugger Robot IInterface(FEntries[I].FValue) := Value;
989*16467b97STreehugger Robot Exit;
990*16467b97STreehugger Robot end;
991*16467b97STreehugger Robot FEntries[FCount].FName := Name;
992*16467b97STreehugger Robot FEntries[FCount].FValue := nil;
993*16467b97STreehugger Robot IInterface(FEntries[FCount].FValue) := Value;
994*16467b97STreehugger Robot FEntries[FCount].FDataType := dtInterface;
995*16467b97STreehugger Robot Inc(FCount);
996*16467b97STreehugger Robot end;
997*16467b97STreehugger Robot
998*16467b97STreehugger Robot end.
999