zeoslib  UNKNOWN
 All Files
ZCollections.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Core collection and map classes }
5 { }
6 { Originally written by Sergey Seroukhov }
7 { }
8 {*********************************************************}
9 
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
12 { }
13 { License Agreement: }
14 { }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
20 { }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
39 { }
40 { }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
45 { }
46 { http://www.sourceforge.net/projects/zeoslib. }
47 { }
48 { }
49 { Zeos Development Group. }
50 {********************************************************@}
51 
52 unit ZCollections;
53 
54 interface
55 
56 {$I ZCore.inc}
57 
58 uses Classes, ZClasses;
59 
60 type
61 
62  {** Implements an iterator for regular TZCollection collection. }
63  TZIterator = class (TZAbstractObject, IZIterator)
64  private
65  FCollection: IZCollection;
66  FCurrentIndex: Integer;
67  public
68  constructor Create(const Col: IZCollection);
69 
70  function HasNext: Boolean;
71  function Next: IZInterface;
72  end;
73 
74  {** Interface list types. }
75  TZInterfaceList = array[0..{$IFDEF WITH_MAXLISTSIZE_DEPRECATED}Maxint div 16{$ELSE}MaxListSize{$ENDIF} - 1] of IZInterface;
76  PZInterfaceList = ^TZInterfaceList;
77 
78  {** Implenments a collection of interfaces. }
79  TZCollection = class(TZAbstractObject, IZCollection, IZClonnable)
80  private
81  FList: PZInterfaceList;
82  FCount: Integer;
83  FCapacity: Integer;
84  protected
85  class procedure Error(const Msg: string; Data: Integer);
86  procedure Grow;
87  procedure SetCapacity(NewCapacity: Integer);
88  procedure SetCount(NewCount: Integer);
89  public
90  constructor Create;
91  destructor Destroy; override;
92 
93  function Clone: IZInterface; override;
94  function ToString: string; override;
95 
96  function Get(Index: Integer): IZInterface;
97  procedure Put(Index: Integer; const Item: IZInterface);
98  function IndexOf(const Item: IZInterface): Integer;
99  function GetCount: Integer;
100  function GetIterator: IZIterator;
101 
102  function First: IZInterface;
103  function Last: IZInterface;
104 
105  function Add(const Item: IZInterface): Integer;
106  procedure Insert(Index: Integer; const Item: IZInterface);
107  function Remove(const Item: IZInterface): Integer;
108 
109  procedure Exchange(Index1, Index2: Integer);
110  procedure Delete(Index: Integer);
111  procedure Clear;
112 
113  function Contains(const Item: IZInterface): Boolean;
114  function ContainsAll(const Col: IZCollection): Boolean;
115  function AddAll(const Col: IZCollection): Boolean;
116  function RemoveAll(const Col: IZCollection): Boolean;
117 
118  property Count: Integer read GetCount;
119  property Items[Index: Integer]: IZInterface read Get write Put; default;
120  end;
121 
122  {** Implements an unmodifiable collection of interfaces. }
123  TZUnmodifiableCollection = class(TZAbstractObject, IZCollection, IZClonnable)
124  private
125  FCollection: IZCollection;
126  private
127  procedure RaiseException;
128  public
129  constructor Create(Collection: IZCollection);
130  destructor Destroy; override;
131 
132  function Clone: IZInterface; override;
133  function ToString: string; override;
134 
135  function Get(Index: Integer): IZInterface;
136  procedure Put(Index: Integer; const Item: IZInterface);
137  function IndexOf(const Item: IZInterface): Integer;
138  function GetCount: Integer;
139  function GetIterator: IZIterator;
140 
141  function First: IZInterface;
142  function Last: IZInterface;
143 
144  function Add(const Item: IZInterface): Integer;
145  procedure Insert(Index: Integer; const Item: IZInterface);
146  function Remove(const Item: IZInterface): Integer;
147 
148  procedure Exchange(Index1, Index2: Integer);
149  procedure Delete(Index: Integer);
150  procedure Clear;
151 
152  function Contains(const Item: IZInterface): Boolean;
153  function ContainsAll(const Col: IZCollection): Boolean;
154  function AddAll(const Col: IZCollection): Boolean;
155  function RemoveAll(const Col: IZCollection): Boolean;
156 
157  property Count: Integer read GetCount;
158  property Items[Index: Integer]: IZInterface read Get write Put; default;
159  end;
160 
161  {** Implements a hash map of interfaces. }
162  TZHashMap = class(TZAbstractObject, IZHashMap, IZClonnable)
163  private
164  FKeys: IZCollection;
165  FReadOnlyKeys: IZCollection;
166  FValues: IZCollection;
167  FReadOnlyValues: IZCollection;
168  public
169  constructor Create;
170  destructor Destroy; override;
171 
172  function Clone: IZInterface; override;
173 
174  function Get(const Key: IZInterface): IZInterface;
175  procedure Put(const Key: IZInterface; const Value: IZInterface);
176  function GetKeys: IZCollection;
177  function GetValues: IZCollection;
178  function GetCount: Integer;
179 
180  function Remove(Key: IZInterface): Boolean;
181  procedure Clear;
182 
183  property Count: Integer read GetCount;
184  property Keys: IZCollection read GetKeys;
185  property Values: IZCollection read GetValues;
186  end;
187 
188  {** Implements a stack of interfaces. }
189  TZStack = class(TZAbstractObject, IZStack, IZClonnable)
190  private
191  FValues: IZCollection;
192  public
193  constructor Create;
194  destructor Destroy; override;
195 
196  function Clone: IZInterface; override;
197  function ToString: string; override;
198 
199  function Peek: IZInterface;
200  function Pop: IZInterface;
201  procedure Push(Value: IZInterface);
202  function GetCount: Integer;
203 
204  property Count: Integer read GetCount;
205  end;
206 
207 implementation
208 
209 uses SysUtils, ZMessages;
210 
211 {$IFDEF FPC}
212  {$HINTS OFF}
213 {$ENDIF}
214 
215 { TZIterator }
216 
217 {**
218  Creates this iterator for the specified interface list.
219  @param List a list of interfaces.
220 }
221 constructor TZIterator.Create(const Col: IZCollection);
222 begin
223  FCollection := Col;
224  FCurrentIndex := 0;
225 end;
226 
227 {**
228  Checks has the iterated collection more elements.
229  @return <code>True</code> if iterated collection has more elements.
230 }
231 function TZIterator.HasNext: Boolean;
232 begin
233  Result := FCurrentIndex < FCollection.Count;
234 end;
235 
236 {**
237  Gets a next iterated element from the collection.
238  @return a next iterated element from the collection or <code>null</code>
239  if no more elements.
240 }
241 function TZIterator.Next: IZInterface;
242 begin
243  if FCurrentIndex < FCollection.Count then
244  begin
245  Result := FCollection[FCurrentIndex];
246  Inc(FCurrentIndex);
247  end else
248  Result := nil;
249 end;
250 
251 { TZCollection }
252 
253 {**
254  Creates this collection and assignes main properties.
255 }
256 constructor TZCollection.Create;
257 begin
258 end;
259 
260 {**
261  Destroys this object and frees the memory.
262 }
263 destructor TZCollection.Destroy;
264 begin
265  Clear;
266 end;
267 
268 {**
269  Raises a collection error.
270  @param Msg an error message.
271  @param Data a integer value to describe an error.
272 }
273 class procedure TZCollection.Error(const Msg: string; Data: Integer);
274 
275 {$IFNDEF FPC}
276  function ReturnAddr: Pointer;
277  asm
278  MOV EAX,[EBP+4]
279  end;
280 {$ENDIF}
281 
282 begin
283  {$IFDEF FPC}
284  raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
285  {$ELSE}
286  raise EListError.CreateFmt(Msg, [Data]) at ReturnAddr;
287  {$ENDIF}
288 end;
289 
290 {**
291  Increases an element count.
292 }
293 procedure TZCollection.Grow;
294 var
295  Delta: Integer;
296 begin
297  if FCapacity > 64 then
298  Delta := FCapacity div 4
299  else
300  begin
301  if FCapacity > 8 then
302  Delta := 16
303  else
304  Delta := 4;
305  end;
306  SetCapacity(FCapacity + Delta);
307 end;
308 
309 {**
310  Sets a new list capacity.
311  @param NewCapacity a new list capacity.
312 }
313 procedure TZCollection.SetCapacity(NewCapacity: Integer);
314 begin
315 {$IFOPT R+}
316  if (NewCapacity < FCount) or (NewCapacity > {$IFDEF WITH_MAXLISTSIZE_DEPRECATED}Maxint div 16{$ELSE}MaxListSize{$ENDIF}) then
317  Error(SListCapacityError, NewCapacity);
318 {$ENDIF}
319  if NewCapacity <> FCapacity then
320  begin
321  ReallocMem(FList, NewCapacity * SizeOf(IZInterface));
322  if NewCapacity > FCapacity then
323  FillChar(FList^[FCount], (NewCapacity - FCapacity) *
324  SizeOf(IZInterface), 0);
325  FCapacity := NewCapacity;
326  end;
327 end;
328 
329 {**
330  Sets a new element count.
331  @param NewCount a new element count.
332 }
333 procedure TZCollection.SetCount(NewCount: Integer);
334 var
335  I: Integer;
336 begin
337 {$IFOPT R+}
338  if (NewCount < 0) or (NewCount > {$IFDEF WITH_MAXLISTSIZE_DEPRECATED}Maxint div 16{$ELSE}MaxListSize{$ENDIF}) then
339  Error(SListCountError, NewCount);
340 {$ENDIF}
341  if NewCount > FCapacity then
342  SetCapacity(NewCount);
343  if NewCount < FCount then
344  begin
345  for I := FCount - 1 downto NewCount do
346  FList^[I] := nil;
347  end;
348  FCount := NewCount;
349 end;
350 
351 {**
352  Clones the instance of this object.
353  @return a reference to the clonned object.
354 }
355 function TZCollection.Clone: IZInterface;
356 var
357  I: Integer;
358  Collection: IZCollection;
359  Clonnable: IZClonnable;
360 begin
361  Collection := TZCollection.Create;
362  for I := 0 to FCount - 1 do
363  begin
364  if FList^[I].QueryInterface(IZClonnable, Clonnable) = 0 then
365  Collection.Add(Clonnable.Clone)
366  else
367  Collection.Add(FList^[I]);
368  end;
369  Result := Collection;
370 end;
371 
372 {**
373  Adds a new object at the and of this collection.
374  @param Item an object to be added.
375  @return a position of the added object.
376 }
377 function TZCollection.Add(const Item: IZInterface): Integer;
378 begin
379  Result := FCount;
380  if Result = FCapacity then
381  Grow;
382 // FList^[Result] := Item as IZInterface; // enourmous Memory Hole in FPC > 2.0.2 Release
383  FList^[Result] := Item;
384  Inc(FCount);
385 end;
386 
387 {**
388  Adds all elements from the specified collection into this collection.
389  @param Col a collection of objects to be added.
390  @return <code>True</code> is the collection was changed.
391 }
392 function TZCollection.AddAll(const Col: IZCollection): Boolean;
393 var
394  I: Integer;
395 begin
396  Result := Col.Count > 0;
397  for I := 0 to Col.Count - 1 do
398  Add(Col[I]);
399 end;
400 
401 {**
402  Clears the content of this collection.
403 }
404 procedure TZCollection.Clear;
405 begin
406  SetCount(0);
407  SetCapacity(0);
408 end;
409 
410 {**
411  Checks is the specified object is stored in this collection.
412  @return <code>True</code> if the object was found in the collection.
413 }
414 function TZCollection.Contains(const Item: IZInterface): Boolean;
415 begin
416  Result := IndexOf(Item) >= 0;
417 end;
418 
419 {**
420  Checks are all the object in this collection.
421  @param Col a collection of objects to be checked.
422  @return <code>True</code> if all objects are in this collection.
423 }
424 function TZCollection.ContainsAll(const Col: IZCollection): Boolean;
425 var
426  I: Integer;
427 begin
428  Result := Col.Count > 0;
429  for I := 0 to Col.Count - 1 do
430  begin
431  if IndexOf(Col[I]) < 0 then
432  begin
433  Result := False;
434  Break;
435  end;
436  end;
437 end;
438 
439 {**
440  Deletes an object from the specified position.
441 }
442 procedure TZCollection.Delete(Index: Integer);
443 begin
444 {$IFOPT R+}
445  if (Index < 0) or (Index >= FCount) then
446  Error(SListIndexError, Index);
447 {$ENDIF}
448  FList^[Index] := nil;
449  Dec(FCount);
450  if Index < FCount then
451  begin
452  System.Move(FList^[Index + 1], FList^[Index],
453  (FCount - Index) * SizeOf(IZInterface));
454  {now nil pointer or on replacing the entry we'll get a bad interlockdecrement}
455  Pointer(FList^[FCount]) := nil; //see http://sourceforge.net/p/zeoslib/tickets/100/
456  end;
457 end;
458 
459 {**
460  Exchanges two element in the collection.
461  @param Index1 an index of the first element.
462  @param Index2 an index of the second element.
463 }
464 procedure TZCollection.Exchange(Index1, Index2: Integer);
465 var
466  Item: IZInterface;
467 begin
468 {$IFOPT R+}
469  if (Index1 < 0) or (Index1 >= FCount) then
470  Error(SListIndexError, Index1);
471  if (Index2 < 0) or (Index2 >= FCount) then
472  Error(SListIndexError, Index2);
473 {$ENDIF}
474  Item := FList^[Index1];
475  FList^[Index1] := FList^[Index2];
476  FList^[Index2] := Item;
477 end;
478 
479 {**
480  Gets the first element from this collection.
481  @return the first element.
482 }
483 function TZCollection.First: IZInterface;
484 begin
485  Result := Get(0);
486 end;
487 
488 {**
489  Gets a collection element from the specified position.
490  @param Index a position index of the element.
491  @return a requested element.
492 }
493 function TZCollection.Get(Index: Integer): IZInterface;
494 begin
495 {$IFOPT R+}
496  if (Index < 0) or (Index >= FCount) then
497  Error(SListIndexError, Index);
498 {$ENDIF}
499  Result := FList^[Index];
500 end;
501 
502 {**
503  Gets a number of the stored element in this collection.
504  @return a number of stored elements.
505 }
506 function TZCollection.GetCount: Integer;
507 begin
508  Result := FCount;
509 end;
510 
511 {**
512  Gets a created iterator for this collection.
513  @return a created iterator for this collection.
514 }
515 function TZCollection.GetIterator: IZIterator;
516 begin
517  Result := TZIterator.Create(Self);
518 end;
519 
520 {**
521  Defines an index of the specified object inside this colleciton.
522  @param Item an object to be found.
523  @return an object position index or -1 if it was not found.
524 }
525 function TZCollection.IndexOf(const Item: IZInterface): Integer;
526 var
527  I: Integer;
528  Comparable: IZComparable;
529  Unknown: IZInterface;
530 begin
531  Result := -1;
532  if (FCount = 0) or (Item = nil) then
533  Exit;
534 
535  { Find IComparable objects }
536  if Item.QueryInterface(IZComparable, Comparable) = 0 then
537  begin
538  for I := 0 to FCount - 1 do
539  begin
540  if Comparable.Equals(FList^[I]) then
541  begin
542  Result := I;
543  Break;
544  end;
545  end;
546  Comparable := nil;
547  end
548  { Find ordinary objects }
549  else
550  begin
551  Unknown := Item;
552  for I := 0 to FCount - 1 do
553  begin
554  if Unknown = FList^[I] then
555  begin
556  Result := I;
557  Break;
558  end;
559  end;
560  Unknown := nil;
561  end;
562 end;
563 
564 {**
565  Inserts an object into specified position.
566  @param Index a position index.
567  @param Item an object to be inserted.
568 }
569 procedure TZCollection.Insert(Index: Integer; const Item: IZInterface);
570 begin
571 {$IFOPT R+}
572  if (Index < 0) or (Index > FCount) then
573  Error(SListIndexError, Index);
574 {$ENDIF}
575  if FCount = FCapacity then
576  Grow;
577  if Index < FCount then
578  begin
579  System.Move(FList^[Index], FList^[Index + 1],
580  (FCount - Index) * SizeOf(IZInterface));
581  {now nil pointer or on replacing the entry we'll get a bad interlockdecrement}
582  Pointer(Flist^[Index]) := nil; //see http://sourceforge.net/p/zeoslib/tickets/100/
583  end;
584  FList^[Index] := Item;
585  Inc(FCount);
586 end;
587 
588 {**
589  Gets the last object from this collection.
590  @return the last object.
591 }
592 function TZCollection.Last: IZInterface;
593 begin
594  Result := Get(FCount - 1);
595 end;
596 
597 {**
598  Puts a specified object into defined position.
599  @param Index a position index.
600  @param Items ab object to be put.
601 }
602 procedure TZCollection.Put(Index: Integer; const Item: IZInterface);
603 begin
604 {$IFOPT R+}
605  if (Index < 0) or (Index >= FCount) then
606  Error(SListIndexError, Index);
607 {$ENDIF}
608  FList^[Index] := Item;
609 end;
610 
611 {**
612  Removes an existed object which equals to the specified one.
613  @param Item an object to be removed.
614  @return an index of the removed object.
615 }
616 function TZCollection.Remove(const Item: IZInterface): Integer;
617 begin
618  Result := IndexOf(Item);
619  if Result >= 0 then
620  Delete(Result);
621 end;
622 
623 {**
624  Removes all the elements from the specified collection.
625  @param Col a collection of object to be removed.
626  @return <code>True</code> if this collection was changed.
627 }
628 function TZCollection.RemoveAll(const Col: IZCollection): Boolean;
629 var
630  I: Integer;
631 begin
632  Result := False;
633  for I := 0 to Col.Count - 1 do
634  Result := (Remove(Col[I]) >= 0) or Result;
635 end;
636 
637 {**
638  Gets a string representation for this object.
639 }
640 function TZCollection.ToString: string;
641 var
642  I: Integer;
643  TempObject: IZObject;
644 begin
645  Result := '';
646  for I := 0 to FCount - 1 do
647  begin
648  if I > 0 then
649  Result := Result + ',';
650  if FList^[I].QueryInterface(IZObject, TempObject) = 0 then
651  Result := Result + TempObject.ToString
652  else
653  Result := Result + Format('<%p>', [Pointer(FList^[I])]);
654  end;
655  Result := '[' + Result + ']';
656 end;
657 
658 { TZUnmodifiableCollection }
659 
660 {**
661  Constructs this object and assignes main properties.
662  @param Collection an initial modifiable list of interfaces.
663 }
664 constructor TZUnmodifiableCollection.Create(Collection: IZCollection);
665 begin
666  inherited Create;
667  FCollection := Collection;
668 end;
669 
670 {**
671  Destroys this object and frees the memory.
672 }
673 destructor TZUnmodifiableCollection.Destroy;
674 begin
675  FCollection := nil;
676  inherited Destroy;
677 end;
678 
679 {**
680  Clones the instance of this object.
681  @return a reference to the clonned object.
682 }
683 function TZUnmodifiableCollection.Clone: IZInterface;
684 begin
685  Result := TZUnmodifiableCollection.Create(FCollection);
686 end;
687 
688 {**
689  Raises invalid operation exception.
690 }
691 procedure TZUnmodifiableCollection.RaiseException;
692 begin
693  raise EInvalidOperation.Create(SImmutableOpIsNotAllowed);
694 end;
695 
696 {**
697  Adds a new object at the and of this collection.
698  @param Item an object to be added.
699  @return a position of the added object.
700 }
701 function TZUnmodifiableCollection.Add(const Item: IZInterface): Integer;
702 begin
703  Result := -1;
704  RaiseException;
705 end;
706 
707 {**
708  Adds all elements from the specified collection into this collection.
709  @param Col a collection of objects to be added.
710  @return <code>True</code> is the collection was changed.
711 }
712 function TZUnmodifiableCollection.AddAll(const Col: IZCollection): Boolean;
713 begin
714  Result := False;
715  RaiseException;
716 end;
717 
718 {**
719  Clears the content of this collection.
720 }
721 procedure TZUnmodifiableCollection.Clear;
722 begin
723  RaiseException;
724 end;
725 
726 {**
727  Checks is the specified object is stored in this collection.
728  @return <code>True</code> if the object was found in the collection.
729 }
730 function TZUnmodifiableCollection.Contains(const Item: IZInterface): Boolean;
731 begin
732  Result := FCollection.Contains(Item);
733 end;
734 
735 {**
736  Checks are all the object in this collection.
737  @param Col a collection of objects to be checked.
738  @return <code>True</code> if all objects are in this collection.
739 }
740 function TZUnmodifiableCollection.ContainsAll(const Col: IZCollection): Boolean;
741 begin
742  Result := FCollection.ContainsAll(Col);
743 end;
744 
745 {**
746  Deletes an object from the specified position.
747 }
748 procedure TZUnmodifiableCollection.Delete(Index: Integer);
749 begin
750  RaiseException;
751 end;
752 
753 {**
754  Exchanges two element in the collection.
755  @param Index1 an index of the first element.
756  @param Index2 an index of the second element.
757 }
758 procedure TZUnmodifiableCollection.Exchange(Index1, Index2: Integer);
759 begin
760  RaiseException;
761 end;
762 
763 {**
764  Gets the first element from this collection.
765  @return the first element.
766 }
767 function TZUnmodifiableCollection.First: IZInterface;
768 begin
769  Result := FCollection.First;
770 end;
771 
772 {**
773  Gets a collection element from the specified position.
774  @param Index a position index of the element.
775  @return a requested element.
776 }
777 function TZUnmodifiableCollection.Get(Index: Integer): IZInterface;
778 begin
779  Result := FCollection[Index];
780 end;
781 
782 {**
783  Gets a number of the stored element in this collection.
784  @return a number of stored elements.
785 }
786 function TZUnmodifiableCollection.GetCount: Integer;
787 begin
788  Result := FCollection.Count;
789 end;
790 
791 {**
792  Gets a created iterator for this collection.
793  @return a created iterator for this collection.
794 }
795 function TZUnmodifiableCollection.GetIterator: IZIterator;
796 begin
797  Result := TZIterator.Create(Self);
798 end;
799 
800 {**
801  Defines an index of the specified object inside this colleciton.
802  @param Item an object to be found.
803  @return an object position index or -1 if it was not found.
804 }
805 function TZUnmodifiableCollection.IndexOf(const Item: IZInterface): Integer;
806 begin
807  Result := FCollection.IndexOf(Item);
808 end;
809 
810 {**
811  Inserts an object into specified position.
812  @param Index a position index.
813  @param Item an object to be inserted.
814 }
815 procedure TZUnmodifiableCollection.Insert(Index: Integer; const Item: IZInterface);
816 begin
817  RaiseException;
818 end;
819 
820 {**
821  Gets the last object from this collection.
822  @return the last object.
823 }
824 function TZUnmodifiableCollection.Last: IZInterface;
825 begin
826  Result := FCollection.Last;
827 end;
828 
829 {**
830  Puts a specified object into defined position.
831  @param Index a position index.
832  @param Items ab object to be put.
833 }
834 procedure TZUnmodifiableCollection.Put(Index: Integer; const Item: IZInterface);
835 begin
836  RaiseException;
837 end;
838 
839 {**
840  Removes an existed object which equals to the specified one.
841  @param Item an object to be removed.
842  @return an index of the removed object.
843 }
844 function TZUnmodifiableCollection.Remove(const Item: IZInterface): Integer;
845 begin
846  Result := -1;
847  RaiseException;
848 end;
849 
850 {**
851  Removes all the elements from the specified collection.
852  @param Col a collection of object to be removed.
853  @return <code>True</code> if this collection was changed.
854 }
855 function TZUnmodifiableCollection.RemoveAll(const Col: IZCollection): Boolean;
856 begin
857  Result := False;
858  RaiseException;
859 end;
860 
861 {**
862  Gets a string representation for this object.
863 }
864 function TZUnmodifiableCollection.ToString: string;
865 begin
866  Result := FCollection.ToString;
867 end;
868 
869 { TZHashMap }
870 
871 {**
872  Creates this hash map and assignes main properties.
873 }
874 constructor TZHashMap.Create;
875 begin
876  inherited Create;
877  FKeys := TZCollection.Create;
878  FValues := TZCollection.Create;
879  FReadOnlyKeys := TZUnmodifiableCollection.Create(FKeys);
880  FReadOnlyValues := TZUnmodifiableCollection.Create(FValues);
881 end;
882 
883 {**
884  Destroys this object and frees the memory.
885 }
886 destructor TZHashMap.Destroy;
887 begin
888  FReadOnlyKeys := nil;
889  FReadOnlyValues := nil;
890  FKeys := nil;
891  FValues := nil;
892  inherited Destroy;
893 end;
894 
895 {**
896  Clones the instance of this object.
897  @return a reference to the clonned object.
898 }
899 function TZHashMap.Clone: IZInterface;
900 var
901  HashMap: TZHashMap;
902 begin
903  HashMap := TZHashMap.Create;
904  HashMap.FKeys := IZCollection(FKeys.Clone);
905  HashMap.FReadOnlyKeys := IZCollection(FReadOnlyKeys.Clone);
906  HashMap.FValues := IZCollection(FValues.Clone);
907  HashMap.FReadOnlyValues := IZCollection(FReadOnlyValues.Clone);
908  Result := HashMap;
909 end;
910 
911 {**
912  Gets a interface by it's key.
913  @param Key a key interface.
914  @return a found value interface or <code>nil</code> otherwise.
915 }
916 function TZHashMap.Get(const Key: IZInterface): IZInterface;
917 var
918  Index: Integer;
919 begin
920  Index := FKeys.IndexOf(Key);
921  if Index >= 0 then
922  Result := FValues[Index]
923  else
924  Result := nil;
925 end;
926 
927 {**
928  Put a new key/value pair interfaces.
929  @param Key a key interface.
930  @param Value a value interface.
931 }
932 procedure TZHashMap.Put(const Key: IZInterface; const Value: IZInterface);
933 var
934  Index: Integer;
935 begin
936  Index := FKeys.IndexOf(Key);
937  if Index >= 0 then
938  FValues[Index] := Value
939  else
940  begin
941  FKeys.Add(Key);
942  FValues.Add(Value);
943  end;
944 end;
945 
946 {**
947  Gets a readonly collection of keys.
948  @return a readonly collection of keys.
949 }
950 function TZHashMap.GetKeys: IZCollection;
951 begin
952  Result := FReadOnlyKeys;
953 end;
954 
955 {**
956  Gets a readonly collection of values.
957  @return a readonly collection of values.
958 }
959 function TZHashMap.GetValues: IZCollection;
960 begin
961  Result := FReadOnlyValues;
962 end;
963 
964 {**
965  Gets a number of elements in this hash map.
966  @return a number of elements in this hash map.
967 }
968 function TZHashMap.GetCount: Integer;
969 begin
970  Result := FKeys.Count;
971 end;
972 
973 {**
974  Removes the element from the map by it's key.
975  @param Key a key of the element.
976  @return <code>true</code> of the hash map was changed.
977 }
978 function TZHashMap.Remove(Key: IZInterface): Boolean;
979 var
980  Index: Integer;
981 begin
982  Index := FKeys.IndexOf(Key);
983  if Index >= 0 then
984  begin
985  FKeys.Delete(Index);
986  FValues.Delete(Index);
987  Result := True;
988  end
989  else
990  Result := False;
991 end;
992 
993 {**
994  Clears this hash map and removes all elements.
995 }
996 procedure TZHashMap.Clear;
997 begin
998  FKeys.Clear;
999  FValues.Clear;
1000 end;
1001 
1002 { TZStack }
1003 
1004 {**
1005  Constructs this object and assignes the main properties.
1006 }
1007 constructor TZStack.Create;
1008 begin
1009  FValues := TZCollection.Create;
1010 end;
1011 
1012 {**
1013  Destroys this object and cleanups the memory.
1014 }
1015 destructor TZStack.Destroy;
1016 begin
1017  FValues := nil;
1018  inherited Destroy;
1019 end;
1020 
1021 {**
1022  Clones the instance of this object.
1023  @return a reference to the clonned object.
1024 }
1025 function TZStack.Clone: IZInterface;
1026 var
1027  Stack: TZStack;
1028 begin
1029  Stack := TZStack.Create;
1030  Stack.FValues := IZCollection(FValues.Clone);
1031  Result := Stack;
1032 end;
1033 
1034 {**
1035  Gets a count of the stored elements.
1036  @return an elements count.
1037 }
1038 function TZStack.GetCount: Integer;
1039 begin
1040  Result := FValues.Count;
1041 end;
1042 
1043 {**
1044  Gets an element from the top this stack without removing it.
1045  @return an element from the top of the stack.
1046 }
1047 function TZStack.Peek: IZInterface;
1048 begin
1049  if FValues.Count > 0 then
1050  Result := FValues[FValues.Count - 1]
1051  else
1052  Result := nil;
1053 end;
1054 
1055 {**
1056  Gets an element from the top this stack and remove it.
1057  @return an element from the top of the stack.
1058 }
1059 function TZStack.Pop: IZInterface;
1060 begin
1061  if FValues.Count > 0 then
1062  begin
1063  Result := FValues[FValues.Count - 1];
1064  FValues.Delete(FValues.Count - 1);
1065  end
1066  else
1067  Result := nil;
1068 end;
1069 
1070 {**
1071  Puts a new element to the top of this stack.
1072  @param Value a new element to be put.
1073 }
1074 procedure TZStack.Push(Value: IZInterface);
1075 begin
1076  FValues.Add(Value);
1077 end;
1078 
1079 {**
1080  Gets a string representation for this object.
1081 }
1082 function TZStack.ToString: string;
1083 begin
1084  Result := FValues.ToString;
1085 end;
1086 
1087 end.