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>
Pop()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>
Peek()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>;
GetCurrent()89 function GetCurrent: TPair<TKey, TValue>;
90 protected
DoGetCurrent()91 function DoGetCurrent: TPair<TKey, TValue>; override;
DoMoveNext()92 function DoMoveNext: Boolean; override;
93 public
94 constructor Create(const AHashList: THashList<TKey, TValue>);
MoveNext()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> }
GetItem(const Key: TKey)104 function GetItem(const Key: TKey): TValue;
105 procedure SetItem(const Key: TKey; const Value: TValue);
GetCount()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;
TryGetValue(const Key: TKey; out Value: TValue)112 function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
113 procedure AddOrSetValue(const Key: TKey; const Value: TValue);
ContainsKey(const Key: TKey)114 function ContainsKey(const Key: TKey): Boolean;
ContainsValue(const Value: TValue)115 function ContainsValue(const Value: TValue): Boolean;
116 public
117 constructor Create; overload;
118 constructor Create(const ACapacity: Integer); overload;
GetEnumerator()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);
Pop()128 function Pop: T;
Peek()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>
DictionaryToString(const Dict: IDictionary<Integer, IList<IANTLRInterface>>)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>
ListToString(const Coll: IList<IANTLRInterface>)156 class function ListToString(const Coll: IList<IANTLRInterface>): String; overload; static;
ListToString(const Coll: IList<String>)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
THashList(const Key: TKey)191 function THashList<TKey, TValue>.ContainsKey(const Key: TKey): Boolean;
192 begin
193 Result := FDictionary.ContainsKey(Key);
194 end;
195
THashList(const Value: TValue)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
THashList()222 function THashList<TKey, TValue>.GetCount: Integer;
223 begin
224 Result := FDictionary.Count;
225 end;
226
THashList()227 function THashList<TKey, TValue>.GetEnumerator: TEnumerator<TPair<TKey, TValue>>;
228 begin
229 Result := TPairEnumerator.Create(Self);
230 end;
231
GetItemnull232 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
THashList(const Key: TKey;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
THashList()278 function THashList<TKey, TValue>.TPairEnumerator.DoGetCurrent: TPair<TKey, TValue>;
279 begin
280 Result := GetCurrent;
281 end;
282
THashList()283 function THashList<TKey, TValue>.TPairEnumerator.DoMoveNext: Boolean;
284 begin
285 Result := MoveNext;
286 end;
287
THashList()288 function THashList<TKey, TValue>.TPairEnumerator.GetCurrent: TPair<TKey, TValue>;
289 begin
290 Result := FPair;
291 end;
292
THashList()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
TStackList()314 function TStackList<T>.Peek: T;
315 begin
316 Result := GetItem(GetCount - 1);
317 end;
318
Popnull319 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
TCollectionUtils.DictionaryToString(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
TCollectionUtils.ListToString(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
TCollectionUtils.ListToString(const Coll: IList<String>)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