Home | History | Annotate | Download | only in Antlr3.Runtime
      1 unit Antlr.Runtime.Collections;
      2 (*
      3 [The "BSD licence"]
      4 Copyright (c) 2008 Erik van Bilsen
      5 Copyright (c) 2005-2007 Kunle Odutola
      6 All rights reserved.
      7 
      8 Redistribution and use in source and binary forms, with or without
      9 modification, are permitted provided that the following conditions
     10 are met:
     11 1. Redistributions of source code MUST RETAIN the above copyright
     12    notice, this list of conditions and the following disclaimer.
     13 2. Redistributions in binary form MUST REPRODUCE the above copyright
     14    notice, this list of conditions and the following disclaimer in 
     15    the documentation and/or other materials provided with the 
     16    distribution.
     17 3. The name of the author may not be used to endorse or promote products
     18    derived from this software without specific prior WRITTEN permission.
     19 4. Unless explicitly state otherwise, any contribution intentionally 
     20    submitted for inclusion in this work to the copyright owner or licensor
     21    shall be under the terms and conditions of this license, without any 
     22    additional terms or conditions.
     23 
     24 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     25 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     26 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     27 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     29 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     30 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     31 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     33 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34 *)
     35 
     36 interface
     37 
     38 {$IF CompilerVersion < 20}
     39 {$MESSAGE ERROR 'You need Delphi 2009 or higher to use the Antlr runtime'}
     40 {$IFEND}
     41 
     42 uses
     43   Generics.Collections,
     44   Antlr.Runtime.Tools;
     45 
     46 type
     47   /// <summary>
     48   /// An Hashtable-backed dictionary that enumerates Keys and Values in
     49   /// insertion order.
     50   /// </summary>
     51   IHashList<TKey, TValue> = interface(IDictionary<TKey, TValue>)
     52   end;
     53 
     54   /// <summary>
     55   /// Stack abstraction that also supports the IList interface
     56   /// </summary>
     57   IStackList<T> = interface(IList<T>)
     58     { Methods }
     59 
     60     /// <summary>
     61     /// Adds an element to the top of the stack list.
     62     /// </summary>
     63     procedure Push(const Item: T);
     64 
     65     /// <summary>
     66     /// Removes the element at the top of the stack list and returns it.
     67     /// </summary>
     68     /// <returns>The element at the top of the stack.</returns>
     69     function Pop: T;
     70 
     71     /// <summary>
     72     /// Removes the element at the top of the stack list without removing it.
     73     /// </summary>
     74     /// <returns>The element at the top of the stack.</returns>
     75     function Peek: T;
     76   end;
     77 
     78 type
     79   THashList<TKey, TValue> = class(TANTLRObject, IHashList<TKey, TValue>)
     80   strict private
     81     type
     82       TPairEnumerator = class(TEnumerator<TPair<TKey, TValue>>)
     83       private
     84         FHashList: THashList<TKey, TValue>;
     85         FOrderList: IList<TKey>;
     86         FIndex: Integer;
     87         FVersion: Integer;
     88         FPair: TPair<TKey, TValue>;
     89         function GetCurrent: TPair<TKey, TValue>;
     90       protected
     91         function DoGetCurrent: TPair<TKey, TValue>; override;
     92         function DoMoveNext: Boolean; override;
     93       public
     94         constructor Create(const AHashList: THashList<TKey, TValue>);
     95         function MoveNext: Boolean;
     96         property Current: TPair<TKey, TValue> read GetCurrent;
     97       end;
     98   private
     99     FDictionary: IDictionary<TKey, TValue>;
    100     FInsertionOrderList: IList<TKey>;
    101     FVersion: Integer;
    102   protected
    103     { IDictionary<TKey, TValue> }
    104     function GetItem(const Key: TKey): TValue;
    105     procedure SetItem(const Key: TKey; const Value: TValue);
    106     function GetCount: Integer;
    107 
    108     procedure Add(const Key: TKey; const Value: TValue);
    109     procedure Remove(const Key: TKey);
    110     procedure Clear;
    111     procedure TrimExcess;
    112     function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
    113     procedure AddOrSetValue(const Key: TKey; const Value: TValue);
    114     function ContainsKey(const Key: TKey): Boolean;
    115     function ContainsValue(const Value: TValue): Boolean;
    116   public
    117     constructor Create; overload;
    118     constructor Create(const ACapacity: Integer); overload;
    119     function GetEnumerator: TEnumerator<TPair<TKey, TValue>>;
    120 
    121     property Items[const Key: TKey]: TValue read GetItem write SetItem; default;
    122   end;
    123 
    124   TStackList<T> = class(TList<T>, IStackList<T>)
    125   protected
    126     { IStackList<T> }
    127     procedure Push(const Item: T);
    128     function Pop: T;
    129     function Peek: T;
    130   end;
    131 
    132   TCollectionUtils = class
    133   public
    134     /// <summary>
    135     /// Returns a string representation of this IDictionary.
    136     /// </summary>
    137     /// <remarks>
    138     /// The string representation is a list of the collection's elements in the order
    139     /// they are returned by its enumerator, enclosed in curly brackets ("{}").
    140     /// The separator is a comma followed by a space i.e. ", ".
    141     /// </remarks>
    142     /// <param name="dict">Dictionary whose string representation will be returned</param>
    143     /// <returns>A string representation of the specified dictionary or "null"</returns>
    144     class function DictionaryToString(const Dict: IDictionary<Integer, IList<IANTLRInterface>>): String; static;
    145 
    146     /// <summary>
    147     /// Returns a string representation of this IList.
    148     /// </summary>
    149     /// <remarks>
    150     /// The string representation is a list of the collection's elements in the order
    151     /// they are returned by its enumerator, enclosed in square brackets ("[]").
    152     /// The separator is a comma followed by a space i.e. ", ".
    153     /// </remarks>
    154     /// <param name="coll">Collection whose string representation will be returned</param>
    155     /// <returns>A string representation of the specified collection or "null"</returns>
    156     class function ListToString(const Coll: IList<IANTLRInterface>): String; overload; static;
    157     class function ListToString(const Coll: IList<String>): String; overload; static;
    158   end;
    159 
    160 implementation
    161 
    162 uses
    163   Classes,
    164   SysUtils;
    165 
    166 { THashList<TKey, TValue> }
    167 
    168 procedure THashList<TKey, TValue>.Add(const Key: TKey; const Value: TValue);
    169 begin
    170   FDictionary.Add(Key, Value);
    171   FInsertionOrderList.Add(Key);
    172   Inc(FVersion);
    173 end;
    174 
    175 procedure THashList<TKey, TValue>.AddOrSetValue(const Key: TKey;
    176   const Value: TValue);
    177 begin
    178   if FDictionary.ContainsKey(Key) then
    179     SetItem(Key, Value)
    180   else
    181     Add(Key, Value);
    182 end;
    183 
    184 procedure THashList<TKey, TValue>.Clear;
    185 begin
    186   FDictionary.Clear;
    187   FInsertionOrderList.Clear;
    188   Inc(FVersion);
    189 end;
    190 
    191 function THashList<TKey, TValue>.ContainsKey(const Key: TKey): Boolean;
    192 begin
    193   Result := FDictionary.ContainsKey(Key);
    194 end;
    195 
    196 function THashList<TKey, TValue>.ContainsValue(const Value: TValue): Boolean;
    197 begin
    198   Result := FDictionary.ContainsValue(Value);
    199 end;
    200 
    201 constructor THashList<TKey, TValue>.Create;
    202 begin
    203   Create(-1);
    204 end;
    205 
    206 constructor THashList<TKey, TValue>.Create(const ACapacity: Integer);
    207 begin
    208   inherited Create;
    209   if (ACapacity < 0) then
    210   begin
    211     FDictionary := TDictionary<TKey, TValue>.Create;
    212     FInsertionOrderList := TList<TKey>.Create;
    213   end
    214   else
    215   begin
    216     FDictionary := TDictionary<TKey, TValue>.Create(ACapacity);
    217     FInsertionOrderList := TList<TKey>.Create;
    218     FInsertionOrderList.Capacity := ACapacity;
    219   end;
    220 end;
    221 
    222 function THashList<TKey, TValue>.GetCount: Integer;
    223 begin
    224   Result := FDictionary.Count;
    225 end;
    226 
    227 function THashList<TKey, TValue>.GetEnumerator: TEnumerator<TPair<TKey, TValue>>;
    228 begin
    229   Result := TPairEnumerator.Create(Self);
    230 end;
    231 
    232 function THashList<TKey, TValue>.GetItem(const Key: TKey): TValue;
    233 begin
    234   Result := FDictionary[Key];
    235 end;
    236 
    237 procedure THashList<TKey, TValue>.Remove(const Key: TKey);
    238 begin
    239   FDictionary.Remove(Key);
    240   FInsertionOrderList.Remove(Key);
    241   Inc(FVersion);
    242 end;
    243 
    244 procedure THashList<TKey, TValue>.SetItem(const Key: TKey; const Value: TValue);
    245 var
    246   IsNewEntry: Boolean;
    247 begin
    248   IsNewEntry := (not FDictionary.ContainsKey(Key));
    249   FDictionary[Key] := Value;
    250   if (IsNewEntry) then
    251     FInsertionOrderList.Add(Key);
    252   Inc(FVersion);
    253 end;
    254 
    255 procedure THashList<TKey, TValue>.TrimExcess;
    256 begin
    257   FDictionary.TrimExcess;
    258   FInsertionOrderList.Capacity := FDictionary.Count;
    259 end;
    260 
    261 function THashList<TKey, TValue>.TryGetValue(const Key: TKey;
    262   out Value: TValue): Boolean;
    263 begin
    264   Result := FDictionary.TryGetValue(Key,Value);
    265 end;
    266 
    267 { THashList<TKey, TValue>.TPairEnumerator }
    268 
    269 constructor THashList<TKey, TValue>.TPairEnumerator.Create(
    270   const AHashList: THashList<TKey, TValue>);
    271 begin
    272   inherited Create;
    273   FHashList := AHashList;
    274   FVersion := FHashList.FVersion;
    275   FOrderList := FHashList.FInsertionOrderList;
    276 end;
    277 
    278 function THashList<TKey, TValue>.TPairEnumerator.DoGetCurrent: TPair<TKey, TValue>;
    279 begin
    280   Result := GetCurrent;
    281 end;
    282 
    283 function THashList<TKey, TValue>.TPairEnumerator.DoMoveNext: Boolean;
    284 begin
    285   Result := MoveNext;
    286 end;
    287 
    288 function THashList<TKey, TValue>.TPairEnumerator.GetCurrent: TPair<TKey, TValue>;
    289 begin
    290   Result := FPair;
    291 end;
    292 
    293 function THashList<TKey, TValue>.TPairEnumerator.MoveNext: Boolean;
    294 begin
    295   if (FVersion <> FHashList.FVersion) then
    296     raise EInvalidOperation.Create('Collection was modified; enumeration operation may not execute.');
    297   if (FIndex < FOrderList.Count) then
    298   begin
    299     FPair.Key := FOrderList[FIndex];
    300     FPair.Value := FHashList[FPair.Key];
    301     Inc(FIndex);
    302     Result := True;
    303   end
    304   else
    305   begin
    306     FPair.Key := Default(TKey);
    307     FPair.Value := Default(TValue);
    308     Result := False;
    309   end;
    310 end;
    311 
    312 { TStackList<T> }
    313 
    314 function TStackList<T>.Peek: T;
    315 begin
    316   Result := GetItem(GetCount - 1);
    317 end;
    318 
    319 function TStackList<T>.Pop: T;
    320 var
    321   I: Integer;
    322 begin
    323   I := GetCount - 1;
    324   Result := GetItem(I);
    325   Delete(I);
    326 end;
    327 
    328 procedure TStackList<T>.Push(const Item: T);
    329 begin
    330   Add(Item);
    331 end;
    332 
    333 { TCollectionUtils }
    334 
    335 class function TCollectionUtils.DictionaryToString(
    336   const Dict: IDictionary<Integer, IList<IANTLRInterface>>): String;
    337 var
    338   SB: TStringBuilder;
    339   I: Integer;
    340   E: TPair<Integer, IList<IANTLRInterface>>;
    341 begin
    342   SB := TStringBuilder.Create;
    343   try
    344     if Assigned(Dict) then
    345     begin
    346       SB.Append('{');
    347       I := 0;
    348       for E in Dict do
    349       begin
    350         if (I > 0) then
    351           SB.Append(', ');
    352         SB.AppendFormat('%d=%s', [E.Key, ListToString(E.Value)]);
    353         Inc(I);
    354       end;
    355       SB.Append('}');
    356     end
    357     else
    358       SB.Insert(0, 'null');
    359     Result := SB.ToString;
    360   finally
    361     SB.Free;
    362   end;
    363 end;
    364 
    365 class function TCollectionUtils.ListToString(
    366   const Coll: IList<IANTLRInterface>): String;
    367 var
    368   SB: TStringBuilder;
    369   I: Integer;
    370   Element: IANTLRInterface;
    371   Dict: IDictionary<Integer, IList<IANTLRInterface>>;
    372   List: IList<IANTLRInterface>;
    373 begin
    374   SB := TStringBuilder.Create;
    375   try
    376     if (Coll <> nil) then
    377     begin
    378       SB.Append('[');
    379       for I := 0 to Coll.Count - 1 do
    380       begin
    381         if (I > 0) then
    382           SB.Append(', ');
    383         Element := Coll[I];
    384         if (Element = nil) then
    385           SB.Append('null')
    386         else
    387         if Supports(Element, IDictionary<Integer, IList<IANTLRInterface>>, Dict) then
    388           SB.Append(DictionaryToString(Dict))
    389         else
    390         if Supports(Element, IList<IANTLRInterface>, List) then
    391           SB.Append(ListToString(List))
    392         else
    393           SB.Append(Element.ToString);
    394       end;
    395       SB.Append(']');
    396     end
    397     else
    398       SB.Insert(0, 'null');
    399     Result := SB.ToString;
    400   finally
    401     SB.Free;
    402   end;
    403 end;
    404 
    405 class function TCollectionUtils.ListToString(const Coll: IList<String>): String;
    406 var
    407   SB: TStringBuilder;
    408   I: Integer;
    409 begin
    410   SB := TStringBuilder.Create;
    411   try
    412     if (Coll <> nil) then
    413     begin
    414       SB.Append('[');
    415       for I := 0 to Coll.Count - 1 do
    416       begin
    417         if (I > 0) then
    418           SB.Append(', ');
    419         SB.Append(Coll[I]);
    420       end;
    421       SB.Append(']');
    422     end
    423     else
    424       SB.Insert(0, 'null');
    425     Result := SB.ToString;
    426   finally
    427     SB.Free;
    428   end;
    429 end;
    430 
    431 end.
    432