Class Information:
| ClassPath: | MEng.System.Runtime.Vector |
| Parent ClassPath: | MEng.System.Runtime.Collection |
| Copyable: | Yes |
| Final: | No (Abstract) |
Vectors are ordered, random access, collection of objects. Ordered means that you put them into the vector in a given order and that order is maintained. A collection is just a term that describes a type of class whose only job is to hold objects of some other class, like a grocery bag is designed just to hold other items. Random access means that you can jump into the list and get to any element you want directly. This is not necessarily true of all types of collections.
Vectors are ordered via a numerical index, so the first element you add will be at the 0th index, the next one at the 1st index and so forth. You can access any particular element via the element's index number. You can also remove all elements or remove specific elements.
The Vector class is an abstract class which you cannot use directly. Instead, you use it to create nested vector types within your own classes. A vector holds other objects, and therefore it requires methods for adding those types of objects into it, and for accessing those objects once they are in the vector. So when you declare a nested vector type, a new class is implicitly generated for you, whose base class is this Vector class. You generate such a class like this:
Class=[NonFinal]
ClassPath MEng.User.MyMacro;
ParentClass MEng.Object;
EndClass;
Types=
VectorOf[Card4] FldIdList;
EndTypes;
Members=
FldIdList m_MyList;
EndMembers;
Use the VectorOf keyword, followed by the bracketed name of the type of objects you want your vector to hold. As is always the case with nested types, the actual classpath of your implicitly generated type is built from your class name plus the nested class name. So, in the example above, the class would be "MEng.User.MyMacro.FldIdList".
The class will have a set of methods that it inherits from Vector, plus a couple which are generated on the fly by the compiler to handle the type specific operations of adding or accessing the elements. One of them is the indexing operator, which allows you to access elements of the vector, which you would do like this (building on our example above.)
CurVal := m_MyList[0];
In this case, the 0th element is indexed via the [] type indexing brackets commonly used in many languages to indicate access to a particular item within a list.
CML collections hold copies of the elements you put into them, not the originals. So you can only instantiate collections for classes that are copyable. It also means that, for large objects, it might be best to add a default constructed object first, and then get access to the object and fill it in. This is more efficient than filling in an object only to copy it into the collection. Note that, since the collection only holds copies, there are no aliasing issues involved.
When you access an element in a collection, you are looking at the literal object, not a copy of it. It would be grossly inefficient to have to copy a big object out of the collection in order to access a field of that element. In the access example above, the element itself is being copied since that is what the writer wanted to do. But if the element had been, for instance, a string, we could do this:
CharCount := m_MyList[0].GetLength();
In this case the m_MyList[0] part accesses the string at the 0th element, and then we call a method on that string object. More importantly, if you called a method that changed the string, you would change the actual string object in the collection, not a copy of it. The elements in a collection are const if the collection is const, and vice versa, so the above example would be illegal if the collection was const.
Note that this may seem counter to the CML rule that you can never look directly at the members of a class, but the elements put into a collection are not members of the collection, they are just contained objects. You cannot look at the class members of the vector directly, only the objects that it holds.
Constructors:
Constructor();
There is one default constructor which creates an empty vector ready to use.
Final, Const Methods:
operator[]([In] MEng.Card4 Index) Returns TYPE;
Returns the Index'th element of the vector. It returns the actual object, not a copy of it, so any methods called on the object affect the element in the vector. Note that this method is const since it does not affect the vector itself, but the object returned will be const if the vector is const, or non-const if the vector is non-const.
TYPE here refers to the actual type for which the vector was instantiated.
GetElemCount() Returns MEng.Card4;
Returns the count of elements currently in the vector. If the vector is empty, the return is zero. You can also use the IsEmpty() method below to test specifically for zero elements, to make the code more self-documenting.
IsEmpty();
Returns true if the vector contains no methods, else returns false. It is equivalent to calling GetElemCount() and checking for a zero return.
Final, Non-Const Methods:
AddObject([In] TYPE ToAdd);
Adds an object to the vector. TYPE in this case refers to the actual type for which the vector was instantiated. A copy of the passed object is made and that copy is what is added to the vector.
InsertObject([In] TYPE ToAdd, [In] MEng.Card4 AtIndex);
Insert an object into the vector. TYPE in this case refers to the actual type for which the vector was instantiated. A copy of the passed object is made and that copy is what is inserted. Any objects in the vector, from the insert index to the end, are pushed forward to make a hole into which the new object is copied.
RemoveAll();
Removes all objects from the vector, leaving it empty.
RemoveAt([In] MEng.Card4 At);
Removes the element from the vector at the indicated index. The vector is compacted to fill in the gap this creates, if At is not the index of the last element.
- If you remove an item while in a loop, be sure to adjust for this in your loop counter, because the count of items is now one fewer than it was!
Obviously removing an item from a big list, and doing this often, while be a somewhat high overhead operation because all of the objects have to be moved downwards in order to compact the list.