Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Interfaces and Collection Classes in Delphi


December 2001/Interfaces and Collection Classes in Delphi

Example 1: The declaration for the basic interfaces in the collection framework

type
  ICollectible = interface
  ['{618977E1-1ADA-11D3-B1A8-00105AA9C2AD}']
    // Return a value < 0 if Self<Obj
    //                = 0 if Self=Obj
    //                > 0 if Self>Obj
    function CompareTo(const Obj: ICollectible): Integer;
    // Return a unique hash value. If two objects are equal (Compare=0)
    // their hash values must also be equal, but the reverse is not
    // necessarily true.
    function HashValue: THashValue;
  end;

  // For use in Maps. A Map is a Set where every member of the set
  // is an IAssociation. An assocation associates a key and a value.
  // The Map uses the key to determine set membership; the value just
  // tags along for good luck.
  IAssociation = interface
  ['{6CF8D12F-16D3-11D3-B1A8-00105AA9C2AD}']
    procedure GetKey(out Key: ICollectible);
    procedure GetValue(out Value: IUnknown);
    procedure SetValue(Value: IUnknown);
  end;

  // The array types are used by enumerators to fetch multiple items from
  // a collection. Usually, you will use the dynamic arrays, but you can
  // use the static arrays, if you prefer.
  TCollectibleArray = array of ICollectible;
  TAssociationArray = array of IAssociation;

  TStaticCollectibleArray = array[0..MaxListSize-1] of ICollectible;
  TStaticAssociationArray = array[0..MaxListSize-1] of IAssociation;

  // User-supplied function; return True to continue, False to abort.
  TCollectionProc = function (Obj: ICollectible): Boolean of object;
  TAssociationProc = function (Key: ICollectible; Value: IUnknown): 
                             Boolean of object;

  IEnumerator = interface;
  ICollection = interface
  ['{618977E3-1ADA-11D3-B1A8-00105AA9C2AD}']
    // Add one or more items to the collection.
    procedure Add(Obj: ICollectible);
    procedure AddAll(Collection: ICollection);

    // Remove all items from the collection.
    procedure Clear;

    // Make a copy of this collection. Do not copy the items in the collection,
    // but keep references to the same items.
    procedure Clone(out Collection: ICollection);

    // Return true when the collection contains the object.
    function Contains(const Obj: ICollectible): Boolean;
    // Return true if this collection contains all of the items in "Collection",
    // in any order.
    function ContainsAll(const Collection: ICollection): Boolean;

    // Count the number of items matching the given item.
    function CountMatching(const Obj: ICollectible): Integer;

    // Return a new enumerator for this collection. Do not modify the collection
    // while the enumerator is active. You can have any number of enumerators
    // for each collection.
    procedure Enumerator(out Enum: IEnumerator); overload;

    // Look for the first matching object and get a reference to the
    // object in the collection. Return True if found, False if not found.
    // Set Found to nil if not found.
    function Find(const SearchFor: ICollectible; out Found: ICollectible):
                 Boolean;

    // Call Proc for each item in the collection.
    procedure ForEach(Proc: TCollectionProc); overload;

    // Return the number of items in the collection.
    function GetCount: Integer;

    // Tell the collection how to handle duplicate items. Some collections
    // do not let you change the duplicates behavior, and will raise an
    // exception if you try to set Duplicates to an invalid value.
    function GetDuplicates: TDuplicates;
    procedure SetDuplicates(Dup: TDuplicates);

    // Return True if Count=0, False if Count>0.
    function IsEmpty: Boolean;

    // Return true if the other collection has the same contents.
    function IsEqual(const Collection: ICollection): Boolean;

    // Query the collection class and return True if:
    // IsMap: the collection is a map collection
    // IsSorted: the collection puts items into sorted order
    // IsOrdered: the collection preserves the order in which items are added
    function IsMap: Boolean;
    function IsSorted: Boolean;
    function IsOrdered: Boolean;

    // Remove the first occurence of an item from the collection.
    // Raise EItemNotFound if it is not in the collection.
    procedure Remove(const Obj: ICollectible);

    // Remove all occurences of an item from the collection.
    // Do nothing if the item is not in the collection.
    procedure RemoveAll(const Obj: ICollectible); overload;

    // Remove all occurences of all the items in Collection.
    // Raise an exception if any item is not in this collection.
    procedure RemoveAll(const Collection: ICollection); overload;

    // Remove all objects EXCEPT those in "Collection".
    procedure RetainAll(const Collection: ICollection);

    // Return a dynamic array that contains the same items as this collection.
    function ToArray: TCollectibleArray;

    property Count: Integer read GetCount;
    property Duplicates: TDuplicates read GetDuplicates write SetDuplicates;
  end;

  IEnumerator = interface
  ['{618977E4-1ADA-11D3-B1A8-00105AA9C2AD}']
    // Make a copy of this iterator, iterating over the same collection,
    // from the same position.
    procedure Clone(out Enum: IEnumerator);

    // Return True if another item is available to be retrieved by Next,
    // or False if the next call to Next will fail.
    function HasNext: Boolean;

    // Get the next item or items in the collection. Choose the dynamic array
    // or static array for returning multiple items. NumFetched tells you how
    // many items were fetched. For a dynamic array, the array size tells you
    // how many items were fetched.
    // The last forms of Next fetches at most one item, returning False
    // if no more items can be fetched.
    procedure Next(Count: Integer; out ResultArray: TCollectibleArray);
                  overload;
    procedure Next(Count: Integer; var ResultArray: 
                   TStaticCollectibleArray; var NumFetched: Integer); overload;
    function Next(out Obj: ICollectible): Boolean; overload;

    // Remove the item that was most recently fetched by Next.
    // A subsequent call to Next fetches the item immediately
    // after the item that was removed. If Next failed or was not
    // called first, Remove raises an exception.
    procedure Remove;

    // Reset the enumerator so Next will fetch the first item.
    procedure Reset;

    // Try to skip over Count items in the collection. Return the number
    // of items actually skipped.
    function Skip(Count: Integer = 1): Integer;
  end;

  // A set contains at most one occurence of an item (Duplicates = dupIgnore).
  ISet = interface(ICollection)
  ['{6CF8D136-16D3-11D3-B1A8-00105AA9C2AD}']
  end;
  IEnumSet = interface(IEnumerator)
  ['{6CF8D137-16D3-11D3-B1A8-00105AA9C2AD}']
  end;

  // A list contains items in a specific order.
  IList = interface(ICollection)
  ['{618977E5-1ADA-11D3-B1A8-00105AA9C2AD}']
    function GetItems(Index: Integer): ICollectible;
    procedure SetItems(Index: Integer; Item: ICollectible);
    function IndexOf(const Item: ICollectible): Integer;

    // A list is special and allows adding and deleting an item
    // at a specific index.
    procedure Delete(Index: Integer);
    procedure Insert(Index: Integer; Obj: ICollectible);
    procedure GetItem(Index: Integer; out Item: ICollectible);

    property Items[Index: Integer]: ICollectible read GetItems write SetItems; 
                                  default;
  end;
  IEnumList = interface(IEnumerator)
  ['{618977E6-1ADA-11D3-B1A8-00105AA9C2AD}']
  end;

  IStack = interface(ICollection)
  ['{E7A78232-1C36-11D3-B1A8-00105AA9C2AD}']
    // Get the top of stack. Return True for success, False if stack if empty.
    function GetTop(out Top: ICollectible): Boolean;
    // Add an item to the stack.
    procedure Push(Obj: ICollectible);
    // Get the top of stack and remove it.
    function Pop(out Top: ICollectible): Boolean;
  end;

  // A map stores key/value pairs. Lookup, remove, etc., by key or value.
  // Access by key is fast; access by value is possible, but requires
  // a linear search over the entire collection. The value can usually be
  // any IUnknown, but if you want to search by value, the value must
  // implement ICollectible.
  // The inherited method--Add, Contains, Find, and Remove--take associations
  // as arguments or return IAssociation objects as results.
  IEnumMap = interface;
  IMap = interface(ICollection)
  ['{6CF8D130-16D3-11D3-B1A8-00105AA9C2AD}']
    procedure Add(Assoc: IAssociation); overload;
    procedure Add(Key: ICollectible; Value: IUnknown); overload;
    procedure Enumerator(out Enum: IEnumMap); overload;
    function FindKey(const Key: ICollectible; out Assoc: IAssociation): Boolean;
    function FindValue(const Value: ICollectible; out Assoc: IAssociation): 
                     Boolean;
    procedure RemoveKey(const Key: ICollectible);
    procedure RemoveValue(const Value: ICollectible);
    function ContainsKey(const Key: ICollectible): Boolean;
    function ContainsValue(const Value: ICollectible): Boolean;

    // Call Proc for each association in the map.
    procedure ForEach(Proc: TAssociationProc); overload;

    // Get the value for a key, or raise an EItemNotFound exception.
    function GetPropValue(const Key: ICollectible): IUnknown;
    procedure SetPropValue(const Key: ICollectible; Value: IUnknown);

    // Get a value for a key, and return True if found or False if not found.
    function GetValue(const Key: ICollectible; out Value: IUnknown): Boolean;

    // Get a set of just the keys.
    procedure GetKeys(out Keys: ISet);
    // Get a collection of just the values. The values must implement
    // ICollectible.
    procedure GetValues(out Values: ICollection);

    property Value[const Key: ICollectible]: IUnknown read GetPropValue 
                                          write SetPropValue; default;
  end;

  // The inherited Next methods fetch associations, but cast as ICollectible.
  // For your convenience, you can use the additional Next methods, which
  // explicitly use IAssociation results. The NextKey methods fetch the
  // next association, but return only the key part.
  IEnumMap = interface(IEnumerator)
  ['{6CF8D131-16D3-11D3-B1A8-00105AA9C2AD}']
    procedure  Next(Count: Integer; out ResultArray: TAssociationArray); 
                                                                overload;
    procedure Next(Count: Integer; var ResultArray: TStaticAssociationArray; 
                  var NumFetched: Integer); overload;
    function Next(out Obj: IAssociation): Boolean; overload;
    function NextKey(out Obj: ICollectible): Boolean; overload;
  end;

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.