1 {*********************************************************}
3 { Zeos Database Objects }
4 { Core collection and map classes }
6 { Originally written by Sergey Seroukhov }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
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. }
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. }
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) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
58 uses Classes, ZClasses;
62 {** Implements an iterator for regular TZCollection collection. }
63 TZIterator = class (TZAbstractObject, IZIterator)
65 FCollection: IZCollection;
66 FCurrentIndex: Integer;
68 constructor Create(const Col: IZCollection);
70 function HasNext: Boolean;
71 function Next: IZInterface;
74 {** Interface list types. }
75 TZInterfaceList = array[0..{$IFDEF WITH_MAXLISTSIZE_DEPRECATED}Maxint div 16{$ELSE}MaxListSize{$ENDIF} - 1] of IZInterface;
76 PZInterfaceList = ^TZInterfaceList;
78 {** Implenments a collection of interfaces. }
79 TZCollection = class(TZAbstractObject, IZCollection, IZClonnable)
81 FList: PZInterfaceList;
85 class procedure Error(const Msg: string; Data: Integer);
87 procedure SetCapacity(NewCapacity: Integer);
88 procedure SetCount(NewCount: Integer);
91 destructor Destroy; override;
93 function Clone: IZInterface; override;
94 function ToString: string; override;
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;
102 function First: IZInterface;
103 function Last: IZInterface;
105 function Add(const Item: IZInterface): Integer;
106 procedure Insert(Index: Integer; const Item: IZInterface);
107 function Remove(const Item: IZInterface): Integer;
109 procedure Exchange(Index1, Index2: Integer);
110 procedure Delete(Index: Integer);
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;
118 property Count: Integer read GetCount;
119 property Items[Index: Integer]: IZInterface read Get write Put; default;
122 {** Implements an unmodifiable collection of interfaces. }
123 TZUnmodifiableCollection = class(TZAbstractObject, IZCollection, IZClonnable)
125 FCollection: IZCollection;
127 procedure RaiseException;
129 constructor Create(Collection: IZCollection);
130 destructor Destroy; override;
132 function Clone: IZInterface; override;
133 function ToString: string; override;
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;
141 function First: IZInterface;
142 function Last: IZInterface;
144 function Add(const Item: IZInterface): Integer;
145 procedure Insert(Index: Integer; const Item: IZInterface);
146 function Remove(const Item: IZInterface): Integer;
148 procedure Exchange(Index1, Index2: Integer);
149 procedure Delete(Index: Integer);
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;
157 property Count: Integer read GetCount;
158 property Items[Index: Integer]: IZInterface read Get write Put; default;
161 {** Implements a hash map of interfaces. }
162 TZHashMap = class(TZAbstractObject, IZHashMap, IZClonnable)
165 FReadOnlyKeys: IZCollection;
166 FValues: IZCollection;
167 FReadOnlyValues: IZCollection;
170 destructor Destroy; override;
172 function Clone: IZInterface; override;
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;
180 function Remove(Key: IZInterface): Boolean;
183 property Count: Integer read GetCount;
184 property Keys: IZCollection read GetKeys;
185 property Values: IZCollection read GetValues;
188 {** Implements a stack of interfaces. }
189 TZStack = class(TZAbstractObject, IZStack, IZClonnable)
191 FValues: IZCollection;
194 destructor Destroy; override;
196 function Clone: IZInterface; override;
197 function ToString: string; override;
199 function Peek: IZInterface;
200 function Pop: IZInterface;
201 procedure Push(Value: IZInterface);
202 function GetCount: Integer;
204 property Count: Integer read GetCount;
209 uses SysUtils, ZMessages;
218 Creates this iterator for the specified interface list.
219 @param List a list of interfaces.
221 constructor TZIterator.Create(const Col: IZCollection);
228 Checks has the iterated collection more elements.
229 @return <code>True</code> if iterated collection has more elements.
231 function TZIterator.HasNext: Boolean;
233 Result := FCurrentIndex < FCollection.Count;
237 Gets a next iterated element from the collection.
238 @return a next iterated element from the collection or <code>null</code>
241 function TZIterator.Next: IZInterface;
243 if FCurrentIndex < FCollection.Count then
245 Result := FCollection[FCurrentIndex];
254 Creates this collection and assignes main properties.
256 constructor TZCollection.Create;
261 Destroys this object and frees the memory.
263 destructor TZCollection.Destroy;
269 Raises a collection error.
270 @param Msg an error message.
271 @param Data a integer value to describe an error.
273 class procedure TZCollection.Error(const Msg: string; Data: Integer);
276 function ReturnAddr: Pointer;
284 raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
286 raise EListError.CreateFmt(Msg, [Data]) at ReturnAddr;
291 Increases an element count.
293 procedure TZCollection.Grow;
297 if FCapacity > 64 then
298 Delta := FCapacity div 4
301 if FCapacity > 8 then
306 SetCapacity(FCapacity + Delta);
310 Sets a new list capacity.
311 @param NewCapacity a new list capacity.
313 procedure TZCollection.SetCapacity(NewCapacity: Integer);
316 if (NewCapacity < FCount) or (NewCapacity > {$IFDEF WITH_MAXLISTSIZE_DEPRECATED}Maxint div 16{$ELSE}MaxListSize{$ENDIF}) then
317 Error(SListCapacityError, NewCapacity);
319 if NewCapacity <> FCapacity then
321 ReallocMem(FList, NewCapacity * SizeOf(IZInterface));
322 if NewCapacity > FCapacity then
323 FillChar(FList^[FCount], (NewCapacity - FCapacity) *
324 SizeOf(IZInterface), 0);
325 FCapacity := NewCapacity;
330 Sets a new element count.
331 @param NewCount a new element count.
333 procedure TZCollection.SetCount(NewCount: Integer);
338 if (NewCount < 0) or (NewCount > {$IFDEF WITH_MAXLISTSIZE_DEPRECATED}Maxint div 16{$ELSE}MaxListSize{$ENDIF}) then
339 Error(SListCountError, NewCount);
341 if NewCount > FCapacity then
342 SetCapacity(NewCount);
343 if NewCount < FCount then
345 for I := FCount - 1 downto NewCount do
352 Clones the instance of this object.
353 @return a reference to the clonned object.
355 function TZCollection.Clone: IZInterface;
358 Collection: IZCollection;
359 Clonnable: IZClonnable;
361 Collection := TZCollection.Create;
362 for I := 0 to FCount - 1 do
364 if FList^[I].QueryInterface(IZClonnable, Clonnable) = 0 then
365 Collection.Add(Clonnable.Clone)
367 Collection.Add(FList^[I]);
369 Result := Collection;
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.
377 function TZCollection.Add(const Item: IZInterface): Integer;
380 if Result = FCapacity then
382 // FList^[Result] := Item as IZInterface; // enourmous Memory Hole in FPC > 2.0.2 Release
383 FList^[Result] := Item;
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.
392 function TZCollection.AddAll(const Col: IZCollection): Boolean;
396 Result := Col.Count > 0;
397 for I := 0 to Col.Count - 1 do
402 Clears the content of this collection.
404 procedure TZCollection.Clear;
411 Checks is the specified object is stored in this collection.
412 @return <code>True</code> if the object was found in the collection.
414 function TZCollection.Contains(const Item: IZInterface): Boolean;
416 Result := IndexOf(Item) >= 0;
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.
424 function TZCollection.ContainsAll(const Col: IZCollection): Boolean;
428 Result := Col.Count > 0;
429 for I := 0 to Col.Count - 1 do
431 if IndexOf(Col[I]) < 0 then
440 Deletes an object from the specified position.
442 procedure TZCollection.Delete(Index: Integer);
445 if (Index < 0) or (Index >= FCount) then
446 Error(SListIndexError, Index);
448 FList^[Index] := nil;
450 if Index < FCount then
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/
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.
464 procedure TZCollection.Exchange(Index1, Index2: Integer);
469 if (Index1 < 0) or (Index1 >= FCount) then
470 Error(SListIndexError, Index1);
471 if (Index2 < 0) or (Index2 >= FCount) then
472 Error(SListIndexError, Index2);
474 Item := FList^[Index1];
475 FList^[Index1] := FList^[Index2];
476 FList^[Index2] := Item;
480 Gets the first element from this collection.
481 @return the first element.
483 function TZCollection.First: IZInterface;
489 Gets a collection element from the specified position.
490 @param Index a position index of the element.
491 @return a requested element.
493 function TZCollection.Get(Index: Integer): IZInterface;
496 if (Index < 0) or (Index >= FCount) then
497 Error(SListIndexError, Index);
499 Result := FList^[Index];
503 Gets a number of the stored element in this collection.
504 @return a number of stored elements.
506 function TZCollection.GetCount: Integer;
512 Gets a created iterator for this collection.
513 @return a created iterator for this collection.
515 function TZCollection.GetIterator: IZIterator;
517 Result := TZIterator.Create(Self);
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.
525 function TZCollection.IndexOf(const Item: IZInterface): Integer;
528 Comparable: IZComparable;
529 Unknown: IZInterface;
532 if (FCount = 0) or (Item = nil) then
535 { Find IComparable objects }
536 if Item.QueryInterface(IZComparable, Comparable) = 0 then
538 for I := 0 to FCount - 1 do
540 if Comparable.Equals(FList^[I]) then
548 { Find ordinary objects }
552 for I := 0 to FCount - 1 do
554 if Unknown = FList^[I] then
565 Inserts an object into specified position.
566 @param Index a position index.
567 @param Item an object to be inserted.
569 procedure TZCollection.Insert(Index: Integer; const Item: IZInterface);
572 if (Index < 0) or (Index > FCount) then
573 Error(SListIndexError, Index);
575 if FCount = FCapacity then
577 if Index < FCount then
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/
584 FList^[Index] := Item;
589 Gets the last object from this collection.
590 @return the last object.
592 function TZCollection.Last: IZInterface;
594 Result := Get(FCount - 1);
598 Puts a specified object into defined position.
599 @param Index a position index.
600 @param Items ab object to be put.
602 procedure TZCollection.Put(Index: Integer; const Item: IZInterface);
605 if (Index < 0) or (Index >= FCount) then
606 Error(SListIndexError, Index);
608 FList^[Index] := Item;
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.
616 function TZCollection.Remove(const Item: IZInterface): Integer;
618 Result := IndexOf(Item);
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.
628 function TZCollection.RemoveAll(const Col: IZCollection): Boolean;
633 for I := 0 to Col.Count - 1 do
634 Result := (Remove(Col[I]) >= 0) or Result;
638 Gets a string representation for this object.
640 function TZCollection.ToString: string;
643 TempObject: IZObject;
646 for I := 0 to FCount - 1 do
649 Result := Result + ',';
650 if FList^[I].QueryInterface(IZObject, TempObject) = 0 then
651 Result := Result + TempObject.ToString
653 Result := Result + Format('<%p>', [Pointer(FList^[I])]);
655 Result := '[' + Result + ']';
658 { TZUnmodifiableCollection }
661 Constructs this object and assignes main properties.
662 @param Collection an initial modifiable list of interfaces.
664 constructor TZUnmodifiableCollection.Create(Collection: IZCollection);
667 FCollection := Collection;
671 Destroys this object and frees the memory.
673 destructor TZUnmodifiableCollection.Destroy;
680 Clones the instance of this object.
681 @return a reference to the clonned object.
683 function TZUnmodifiableCollection.Clone: IZInterface;
685 Result := TZUnmodifiableCollection.Create(FCollection);
689 Raises invalid operation exception.
691 procedure TZUnmodifiableCollection.RaiseException;
693 raise EInvalidOperation.Create(SImmutableOpIsNotAllowed);
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.
701 function TZUnmodifiableCollection.Add(const Item: IZInterface): Integer;
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.
712 function TZUnmodifiableCollection.AddAll(const Col: IZCollection): Boolean;
719 Clears the content of this collection.
721 procedure TZUnmodifiableCollection.Clear;
727 Checks is the specified object is stored in this collection.
728 @return <code>True</code> if the object was found in the collection.
730 function TZUnmodifiableCollection.Contains(const Item: IZInterface): Boolean;
732 Result := FCollection.Contains(Item);
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.
740 function TZUnmodifiableCollection.ContainsAll(const Col: IZCollection): Boolean;
742 Result := FCollection.ContainsAll(Col);
746 Deletes an object from the specified position.
748 procedure TZUnmodifiableCollection.Delete(Index: Integer);
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.
758 procedure TZUnmodifiableCollection.Exchange(Index1, Index2: Integer);
764 Gets the first element from this collection.
765 @return the first element.
767 function TZUnmodifiableCollection.First: IZInterface;
769 Result := FCollection.First;
773 Gets a collection element from the specified position.
774 @param Index a position index of the element.
775 @return a requested element.
777 function TZUnmodifiableCollection.Get(Index: Integer): IZInterface;
779 Result := FCollection[Index];
783 Gets a number of the stored element in this collection.
784 @return a number of stored elements.
786 function TZUnmodifiableCollection.GetCount: Integer;
788 Result := FCollection.Count;
792 Gets a created iterator for this collection.
793 @return a created iterator for this collection.
795 function TZUnmodifiableCollection.GetIterator: IZIterator;
797 Result := TZIterator.Create(Self);
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.
805 function TZUnmodifiableCollection.IndexOf(const Item: IZInterface): Integer;
807 Result := FCollection.IndexOf(Item);
811 Inserts an object into specified position.
812 @param Index a position index.
813 @param Item an object to be inserted.
815 procedure TZUnmodifiableCollection.Insert(Index: Integer; const Item: IZInterface);
821 Gets the last object from this collection.
822 @return the last object.
824 function TZUnmodifiableCollection.Last: IZInterface;
826 Result := FCollection.Last;
830 Puts a specified object into defined position.
831 @param Index a position index.
832 @param Items ab object to be put.
834 procedure TZUnmodifiableCollection.Put(Index: Integer; const Item: IZInterface);
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.
844 function TZUnmodifiableCollection.Remove(const Item: IZInterface): Integer;
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.
855 function TZUnmodifiableCollection.RemoveAll(const Col: IZCollection): Boolean;
862 Gets a string representation for this object.
864 function TZUnmodifiableCollection.ToString: string;
866 Result := FCollection.ToString;
872 Creates this hash map and assignes main properties.
874 constructor TZHashMap.Create;
877 FKeys := TZCollection.Create;
878 FValues := TZCollection.Create;
879 FReadOnlyKeys := TZUnmodifiableCollection.Create(FKeys);
880 FReadOnlyValues := TZUnmodifiableCollection.Create(FValues);
884 Destroys this object and frees the memory.
886 destructor TZHashMap.Destroy;
888 FReadOnlyKeys := nil;
889 FReadOnlyValues := nil;
896 Clones the instance of this object.
897 @return a reference to the clonned object.
899 function TZHashMap.Clone: IZInterface;
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);
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.
916 function TZHashMap.Get(const Key: IZInterface): IZInterface;
920 Index := FKeys.IndexOf(Key);
922 Result := FValues[Index]
928 Put a new key/value pair interfaces.
929 @param Key a key interface.
930 @param Value a value interface.
932 procedure TZHashMap.Put(const Key: IZInterface; const Value: IZInterface);
936 Index := FKeys.IndexOf(Key);
938 FValues[Index] := Value
947 Gets a readonly collection of keys.
948 @return a readonly collection of keys.
950 function TZHashMap.GetKeys: IZCollection;
952 Result := FReadOnlyKeys;
956 Gets a readonly collection of values.
957 @return a readonly collection of values.
959 function TZHashMap.GetValues: IZCollection;
961 Result := FReadOnlyValues;
965 Gets a number of elements in this hash map.
966 @return a number of elements in this hash map.
968 function TZHashMap.GetCount: Integer;
970 Result := FKeys.Count;
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.
978 function TZHashMap.Remove(Key: IZInterface): Boolean;
982 Index := FKeys.IndexOf(Key);
986 FValues.Delete(Index);
994 Clears this hash map and removes all elements.
996 procedure TZHashMap.Clear;
1005 Constructs this object and assignes the main properties.
1007 constructor TZStack.Create;
1009 FValues := TZCollection.Create;
1013 Destroys this object and cleanups the memory.
1015 destructor TZStack.Destroy;
1022 Clones the instance of this object.
1023 @return a reference to the clonned object.
1025 function TZStack.Clone: IZInterface;
1029 Stack := TZStack.Create;
1030 Stack.FValues := IZCollection(FValues.Clone);
1035 Gets a count of the stored elements.
1036 @return an elements count.
1038 function TZStack.GetCount: Integer;
1040 Result := FValues.Count;
1044 Gets an element from the top this stack without removing it.
1045 @return an element from the top of the stack.
1047 function TZStack.Peek: IZInterface;
1049 if FValues.Count > 0 then
1050 Result := FValues[FValues.Count - 1]
1056 Gets an element from the top this stack and remove it.
1057 @return an element from the top of the stack.
1059 function TZStack.Pop: IZInterface;
1061 if FValues.Count > 0 then
1063 Result := FValues[FValues.Count - 1];
1064 FValues.Delete(FValues.Count - 1);
1071 Puts a new element to the top of this stack.
1072 @param Value a new element to be put.
1074 procedure TZStack.Push(Value: IZInterface);
1080 Gets a string representation for this object.
1082 function TZStack.ToString: string;
1084 Result := FValues.ToString;