Defined in List.Def Mixes in with Object Inherits from HasIterator Inherits interface from HasCount
The HasIndexing mixin provides a way for you to create a subclass for which the concept of an index has some meaning. The subclass might have an index field; the subclass might be a linked list (like Linkable) that has an implicit concept of indexing. You override the At method to provide a way to get at objects using the indexing concept. The At method might just read a field, or it might (like Linkable_At) step through some number of links. What the index means is up to youyour class could be a sorted list, or it could be an unsorted collection of objects related in some way.
The HasIndexing mixin differs from the HasCount mixin in that it provides an ordering for a collection, and not just a count.
Remember that if the documentation and the software (especially the definition files) disagree, always trust the software.
Since class HasIndexing is a mixin, you'll never work directly with HasIndexing objects. Instead, you'll work with objects of classes that inherit from the HasIndexing mixin, such as ObjectList. Many of the list classes inherit from the HasIndexing mixin, and so will many of the list subclasses you create. In addition, class Linkable inherits from the HasIndexing mixin, which means that any descendent of class Viewable does as well.
Instantiate: never Subclass: always Call its methods: sometimes
Your subclass must implement the Count method inherited from the HasCount interface.
Your subclass must also implement the At method, a crucial method, since it provides callers a way to get at objects using the indexing concept. You might want to spend time tuning the performance of your At method, since the system calls it quite often.
The HasIndexing class has the following methods you might Call:
Method | Description |
---|---|
Getting elements | |
First | Return the element with index 1 |
FirstNonNil | Return the first object that isn't nilObject |
Last | Return the object with the highest index |
Iterators | |
Each | Call a function on each object |
Searching | |
Search | Return the index of the matching object |
FindAfter | Return the index of the first matching object with index higher than the given number |
FindEqual | Searches using IsEqual to determine equality instead of == |
String matching | |
FindClosestMatch | Returns the index of item (if any) whose search name most closely matches the given string |
FindExactMatch | Returns the index of item (if any) whose search name exactly matches the given string |
SearchForExpansion | Search the collection of objects for a text object that appropriately expands an abbreviation |
Whenever you create a subclass of the HasIndexing class, you must override the following method:
Method | Description |
---|---|
At | Returns the element at the given index |
Count | Returns the number of elements in a collection |
The HasIndexing mixin defines no fields.
operation At(index: Unsigned): Object, noFail, safe Call: often Override: always
Call At to get the object at position index
.
Every time you create a class that inherits from the HasIndexing mixin, you must override At. At should return the object at position index. What the index means for your subclass is something you must determine. At could search for an object with index in a particular field. At could step through index links in a linked list, returning the last object.
The following code fragment shows how the Linkable class defines the At method:
self = First(self); while (--index > 0) if ((self = Next(self)) == nilObject) break; return self;
Apply this example with some care, since Linkable must also override the First method to avoid a nasty case of recursive definitions. Here is another example, this time from the ObjectList definition of At:
ObjectID result; long *ptr = BeginReadFieldsOf(self, Object_); long count = *ptr; EndRead(self); if (index < 1 || index > count) return nilObject; ptr = BeginReadExtra(self); result = *(ptr + index - 1); EndRead(self); return MakeUsable(self, result);
attribute First: Object, readOnly; // operation First(): Object Call: sometimes Override: rarely
Call First to get the object at index 1. First relies on At.
attribute FirstNonNil: Object, readOnly; operation FirstNonNil(): Object Call: sometimes Override: rarely
Call FirstNonNil to get the first object in the group that is not the nil object. FirstNonNil uses the Each method to compare each object with nil.
attribute Last: Object, readOnly; operation Last(): Object Call: sometimes Override: always
Call Last to get the last object in the group, that is, the object whose index number is the number of objects in the group. Last relies on a subclass's implementations of Count and At.
overrides Each(proc: EachFunction; VAR params: Parameters): Object Call: sometimes Override: sometimes
Call Each to call a function on each member of a group.
See the section on HasIterator_Each for a complete discussion of the basic behavior of the Each method. You will see various implementations of Each throughout the Magic Cap system.
HasIndexing_Each relies on your subclass's implementation of At.
Here is an example of how the HasIndexing mixin itself uses Each to define the FirstNonNil method:
Private ObjectID ReturnNonNil(ObjectID item, Parameters *parameters) { #pragma unused (parameters) return item; } Method ObjectID HasIndexing_FirstNonNil(ObjectID self) { ObjectID result = Each(self, ReturnNonNil, nil); if (result == nilObject) Warn(cannotFindIndex); return result; }
operation Search(target: Object): Unsigned, noFail; Call: sometimes Override: sometimes
Call Search to search your collection of objects for a given object. target is the desired object; Search returns the index of the first occurrence of this object in the collection of objects. If the requested object isn't in the collection, the result is zero.
The HasIndexing mixin definition of Search simply calls FindAfter with an afterIndex of 0. (See the description of FindAfter just below this paragraph.) Override Search if your subclass requires a different search algorithm.
operation FindAfter(target:Object; afterIndex: Unsigned): Unsigned, noFail; Call: sometimes Override: sometimes
Given an object ID number, FindAfter searches objects with indices greater than afterIndex. FindAfter returns the index of the first matching object. If no object matches, FindAfter returns 0. FindAfter relies upon the subclass's definition of At.
operation FindClosestMatch(matchString: String; afterIndex: Unsigned; userEntryOrder: Boolean): Unsigned, noFail Call: rarely Override: rarely
Call FindClosestMatch to search an object collection, beginning at a specified index position, for the object whose search name most nearly matches a given string. matchString is the string to match; afterIndex is the index position after which to begin the search.
FindClosestMatch searches the entire list, starting at the specified index and wrapping around from the end of the list to the beginning. (If afterIndex is less than zero or greater than the length of the list, the operation fails with the exception cannotFindIndex.) If it finds an object whose search name exactly matches the requested string, FindClosestMatch immediately returns the index of that object. Otherwise, it scans the entire list until it wraps back around to the original starting index, then returns the index of the object whose search name comes closest to the match string.
The string comparison is case-insensitive: that is, corresponding upper- and lowercase letters are considered equivalent. The standard of "closeness" is the difference in ascii value in the first character position in which the two strings differ. For example, aardvark and gnu are a closer match than aardvark and zebra (because a is closer to g than to z), and antelope and antenna are closer than antelope and anteater (because antel is closer to anten than to antea). See the descriptions of Object_GetSearchName and Card_GetSearchName for more information.
overrides FindExactMatch(matchString: String; afterIndex: Unsigned; userEntryOrder: Boolean): Unsigned, noFail; Call: sometimes Override: rarely
FindExactMatch returns the index of the first item (if any) whose search name matches matchString exactly. See the description of FindClosestMatch above for more information.
overrides SearchForExpansion(prefix: Text; VAR index: Unsigned): Text Call: sometimes Override: rarely
You are probably familiar with Magic Cap's word expansion trick. Word expansion (or completion) allows users to expand an abbreviation into a complete word or phrase by tapping on the "expand" button on the keyboard. The SearchForExpansion method is crucial to classes like WordGuessList and AbbreviationList, which implement word expansion.
Given a prefix and an index, SearchForExpansion looks through the collection of objects (starting with the object at index index) for an expansion match. SearchForExpansion returns a text object containing the expanded word (if it found a match), and puts the index of the matching object in *index.