xref: /aosp_15_r20/external/antlr/runtime/Delphi/Sources/Antlr3.Runtime/Antlr.Runtime.Tools.pas (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
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