Overview

The RoseAggregate class is the base for all EXPRESS array, bag, list, and set classes. Aggregates are strongly typed so sub-classes of RoseArray, RoseBag, RoseList, and RoseSet to handle elements of each type. The aggregate hierarchy is shown below.

  • RoseObject
    • RoseAggregate
      • RoseList
        • ListOfFloat
        • RosePtrList
          • ListOfRoseObject
          • ListOfEntityType
          • ...
      • RoseBag
        • BagOfFloat
        • RosePtrBag
          • BagOfRoseObject
          • BagOfEntityType
          • ...
      • RoseSet
        • SetOfFloat
        • RosePtrSet
        • ...
      • RoseArray
        • ArrayOfFloat
        • RosePtrArray
        • ...
Aggregate Hierarchy

The name of an aggregate class is constructed from the data structure (List, Bag, Set, or Array) and element type, in the form <agg>Of<element> For example, a list of integer elements would be ListOfInteger.

Aggregates classes were available before templates were widely supported, so they are implemented using macros that do not require any special extensions to the C++ compiler.

RoseAggregate Member Functions

The following sections describe functions available on each aggregate class. Some functions are defined by RoseAggregate and some are defined by parameterized subclasses. The documentation for the parameterized functions use the placeholder <class_name> to indicate the C++ class name and the the placeholder <type_ref> to indicate C++ element type. For example:

<class_name>      <type_ref>
ListOfPoint        Point *        /* stores pointer to object */
ListOfRoseObject   RoseObject *   /* stores pointer to object */
ListOfInteger      int            /* stores copy of the integer */
ListOfDouble       double         /* stores copy of the double */
ListOfString       char *         /* stores copy of the string */

In addition, some functions are only applicable to some classes. For example, the insert() operation is only available on lists. These restrictions are described in the documentation for the affected functions.

Predefined Aggregate Classes

The ROSE library defines the following aggregate classes. They are always available and are not regenerated by the EXPRESS compiler.

ListOfBoolean     ArrayOfBoolean     BagOfBoolean     SetOfBoolean
ListOfDouble      ArrayOfDouble      BagOfDouble      SetOfDouble
ListOfFloat       ArrayOfFloat       BagOfFloat       SetOfFloat
ListOfInteger     ArrayOfInteger     BagOfInteger     SetOfInteger
ListOfString      ArrayOfString      BagOfString      SetOfString
ListOfRoseObject  ArrayOfRoseObject  BagOfRoseObject  SetOfRoseObject
ListOfRoseAttribute
ListOfRoseDefType
ListOfRoseDesign
ListOfRoseDomain
ListOfRoseRefined

Functions Inherited from RoseObject

Some RoseObject functions are only appropriate for aggregate instances, but are defined on the root class to simplify late-bound programs.

<type_ref>  RoseObject::get<name>(unsigned index);
 
RoseBoolean RoseObject::isExternal(unsigned index);
RoseBoolean RoseObject::isUnresolved(unsigned index);

RoseBoolean RoseObject::put<name>(<type_ref> value,unsigned index);

unsigned    RoseObject::size();

RoseAggregate Constructor

<class_name>(
	unsigned capacity = 0
	);

Aggregate constructors take an optional capacity. The capacity() is the number of elements allocated by an aggregate for its contents. For arrays, the size is equal to the capacity. For all other aggregates, the size is initially zero. Lists, sets, and bags resize automatically, so the capacity argument is not needed, but can be used to avoid reallocations when the eventual size of an aggregate is known.

ListOfPoint * myPointList = new ListOfPoint (50);

See Also

RoseAggregate::size() (change size)

Operator []

<type_ref> operator[](
	unsigned index
	);

The index operator is a shorthand form of the get() function and returns the element at a given index. It is convenient when working with an aggregate on the stack, while the get() function is more natural when working with a pointer to an aggregate.

Aggregate index values begin at zero. This operator is defined by each parameterized aggregate class. The return value is not an L-value. Use the put() function to change the element.

unsigned i;
ListOfString agg_local;
for (i=0; i<agg_local.size(); i++)
    printf ("Value %u = %s\n", i, agg_local[i]);


SetOfstp_representation_item * agg_ptr;
for (i=0; i<agg_ptr->size(); i++)
    printf ("Value %u = #%lu\n", i, agg_ptr->get(i)->entity_id());

_element()

<type_ref> _element(
	unsigned index
	);

The _element() function returns the element at the specified index. It does no range checking on the index value, so it should be slightly faster than get(). The code below prints the contents of a list of strings. This should be safe because the bounds are already checked by the loop:

ListOfString * strings;
unsigned i, sz;

for (i=0, sz=strings-> size(); i<sz; i++)
     printf (Element %d is %s\n, i, strings-> _element(i));

See Also

RoseObject::get<type>()

add()

<class_name> * add(
	<type_ref> value
	);

The add() function appends a value to the end of an aggregate. This function is only defined by the parameterized list, set, and bag classes. On sets, this function is equivalent to the addIfAbsent()() function, where a value is only added if it is not already present in the set.

The following example creates a new list of strings and populates it with some values.

ListOfString * strings = new ListOfString;

strings->add (string zero);
strings->add (string one);
strings->add (string two);

See Also

RoseAggregate::addObject(); RoseAggregate::insert(); RoseAggregate::put()

addIfAbsent()

<class_name> * addIfAbsent(
	<type_ref> value
	);

The addIfAbsent() function appends a value to an aggregate only if it is not already present. This function is only defined by the list and bag classes. The add() function on sets already performs the same operation.

The following example creates a new list of strings and populates it with some values.

ListOfString * strings = new ListOfString;

strings->addIfAbsent (string zero);
strings->addIfAbsent (string one);
strings->addIfAbsent (string one);   /* no effect */
strings->addIfAbsent (string two);

See Also

RoseAggregate::addObjectIfAbsent(); RoseAggregate::contains()

addObject()

RoseObject * addObject(
	RoseObject * value
	);

The addObject() function is defined by RoseAggregate, but it is only useful for late-bound programming with aggregates of objects. The function appends an object to the end of the aggregate regardless of the type of the aggregate. Arrays are resized by this operation.

The following example uses late-bound programming to create a list of point objects and populate it with a number of new points:

RoseDesign * design;
RoseAggregate * points;

points = ROSE_CAST (RoseAggregate, design-> pnewInstance (ListOfPoint));
points-> addObject (design-> pnewInstance (Point));
points-> addObject (design-> pnewInstance (Point));
points-> addObject (design-> pnewInstance (Point));

If we had the classes available, we could do the same thing using the following early-bound calls:

RoseDesign * design;
ListOfPoint * points;

points = pnewIn (design) ListOfPoint;
points-> add (pnewIn (design) Point);
points-> add (pnewIn (design) Point);
points-> add (pnewIn (design) Point);

The addObject() function can also be simulated by using the RoseObject::putObject() function. The following two statements are equivalent:

points-> addObject (design-> pnewInstance (Point));
points-> putObject (design-> pnewInstance (Point), points-> size());

See Also

RoseAggregate::insertObject(); RoseObject::put<type>()

addObjectIfAbsent()

RoseAggregate * addObjectIfAbsent(
	RoseObject * value
	);

The addObjectIfAbsent() function is only useful for late-bound programming with aggregates of objects. If the object is not in the aggregate, the function will append the object to the end regardless of the type of the aggregate. Arrays are resized by this operation.

The following example uses late-bound programming to create a list of point objects and populate it with a number of new points:

RoseDesign * design;
RoseAggregate * points;
RoseObject * pt1 = design-> pnewInstance (Point);
RoseObject * pt2 = design-> pnewInstance (Point);

points = ROSE_CAST (RoseAggregate, design-> pnewInstance (ListOfPoint));
points-> addObjectIfAbsent (pt1);
points-> addObjectIfAbsent (pt2);
points-> addObjectIfAbsent (pt2);  /* no effect */

See Also

RoseAggregate::addObject(); RoseAggregate::contains()

capacity()

unsigned capacity();

void capacity(
	unsigned new_capacity
	);

The capacity() functions control the number of elements allocated by an aggregate for its contents. When more than this number of elements are put in an aggregate, it will reallocate its internal buffer. If the new capacity would be too small for the current contents of the aggregate, the call is ignored.

Aggregates resize automatically, so this function need not be called by an application. It can be used to avoid successive reallocations when the eventual size of an aggregate is known.

The following example sets the capacity of an aggregate before a large number of additions, which should reduce the a number of reallocations.

ListOfString * strings = new ListOfString;

strings->capacity (5000);
for (unsigned i=0; i< 5000; i++)
    strings->add (some string);

Alternatively, we could specify the capacity as an argument to the aggregate constructor:

ListOfString * strings = new ListOfString (5000);

for (unsigned i=0; i< 5000; i++)
    strings->add (some string);

contains()

RoseBoolean contains(
	<type_ref> value
	);

The contains() function returns true if a value occurrs within the aggregate. Objects are compared by pointer, and strings are compared using strcmp(). Other primitive values are compared directly. This function is defined by each parameterized aggregate class.

The find() function does the same thing, but returns an index position rather than a boolean value.

The following example searches a list of strings for a value.

ListOfString * strings = new ListOfString;

if (strings-> contain (string one))
     printf (The string is present\n);
else printf (The string is not there\n);

emptyYourself()

void emptyYourself();

The emptyYourself() function removes the contents of an aggregate and sets the size of the aggregate to be zero. Objects are removed from the aggregate, but are not destroyed. This is equivalent to setting the size() to zero

The following example creates a new list of strings, populates it with some values and then empties it again.

ListOfString * strings = new ListOfString;

strings->add (string zero);
strings->add (string one);
strings->add (string two);
strings->emptyYourself();       /* cleans it all out again */

find()

unsigned find(
	<type_ref> value
	);

The find() function examines the elements in an aggregate and returns the index of the first occurrence of a value. If the value does not appear in the aggregate, the function returns ROSE_NULL_INDEX. The contains() function just tests whether find() returns a non-null value.

Objects are compared by pointer value and strings are compared using strcmp(). Other primitive values are compared directly. This function is defined by each parameterized aggregate class.

The following example searches a list of strings for a value and prints the index.

ListOfString * strings = new ListOfString;
unsigned idx;

idx = strings-> find (string one);
if (idx == ROSE_NULL_INDEX)
     printf (The string is not there\n);
else printf (The string is at index %d\n, idx);

findObject()

unsigned findObject(
	RoseObject * value
	);

The findObject() function is useful for late-bound programming with aggregates of objects. The function returns the index of the first occurrence of an object within the aggregate, or ROSE_NULL_INDEX if the object is not present. Objects are compared by pointer value.

The following example uses late-bound programming to create a list of point objects, populate it with a number of new points, and then search for one of those points:

RoseDesign * design;
RoseAggregate * points;
RoseObject * pt1 = design-> pnewInstance (Point);
RoseObject * pt2 = design-> pnewInstance (Point);
RoseObject * pt3 = design-> pnewInstance (Point);
unsigned idx;

points = ROSE_CAST (RoseAggregate, design-> pnewInstance (ListOfPoint));
points-> addObject (pt1);
points-> addObject (pt2);
points-> addObject (pt3);

idx = points-> findObject (pt2);
if (idx == ROSE_NULL_INDEX)
     printf (The point is not there\n);
else printf (Point found at index %d\n, idx);

In this example, the point should be found at index position one.

first()

<type_ref> first();

The first() function returns the first element of an aggregate. If the aggregate is empty, the function returns null. This function is defined by each parameterized aggregate class.

The following example prints the first element from a list of strings.

ListOfString * strings;

printf (The first string is %s\n, strings-> first());
printf (The first string is %s\n, strings-> get(0));

get()

<type_ref> get(
	unsigned index
	);

The get() function returns the element at the specified index. If the index is out of bounds, the function will return the null value for the type. Aggregates are indexed beginning at zero. The get() function and the index operator are equivalent, but the index operator is easier to use with aggregates on the stack. This functions are defined by each parameterized aggregate class.

The following example shows some equivalent uses of the get() function and the index operator:

ListOfPoint   ptlist_1;
ListOfPoint * ptlist_2;

/* Each of the expressions return the element at index 3 */
ptlist_1 [3];        ptlist_1.get(3);
(*ptlist_2)[3];      ptlist_2->get(3);

The next example shows a loop that prints the contents of a list of strings:

ListOfString * strings;
unsigned i, sz;

for (i=0, sz=strings-> size(); i<sz; i++)
     printf (Element %d is %s\n, i, strings-> get(i));

See Also

RoseAggregate::_element(); RoseObject::get<type>()

insert()

<class_name> *  insert(
	<type_ref> value,
	unsigned index
	);

The insert() function inserts a value into the middle of a list. The new value is placed at the index. The values previously at the index and all that follow it are shifted up by one position. Aggregates are indexed beginning at zero. This function is only defined by subtypes of RoseList.

The following example creates a new list of strings, populates it with some values, and then inserts some values in the middle.

ListOfString * strings = new ListOfString;

strings->add (string zero);
strings->add (string one);
strings->add (string two);
strings->insert (interloper, 1);

The result of this is a list with four elements. The interloper string appears between strings zero and one. An insert() beyond the end of a list behaves in the same way as a put() beyond the end of a list. The following example shows how the insert() function can be used in place of the add() function.

ListOfString * strings = new ListOfString;

strings->insert (string zero,  strings->size());
strings->insert (string one,   strings->size());
strings->insert (string two,   strings->size());

insertObject()

RoseAggregate * insertObject(
	RoseObject * value,
	unsigned index = ROSE_NULL_INDEX
	);

The insertObject() function is useful for late-bound programming with aggregates of objects. The function inserts an object into the middle of an aggregate. The new object is placed at the index. The objects previously at the index and all that follow it are shifted up one position. Aggregates are indexed beginning at zero. If you omit the index parameter, this function is equivalent to addObject().

The following example uses late-bound programming to create a list of point objects, populate it with two new points, and then insert a third between the first two:

RoseDesign * design;
RoseAggregate * points;
RoseObject * pt1 = design-> pnewInstance (Point);
RoseObject * pt2 = design-> pnewInstance (Point);
RoseObject * pt3 = design-> pnewInstance (Point);
unsigned idx;

points = ROSE_CAST (RoseAggregate, design-> pnewInstance (ListOfPoint));
points-> addObject (pt1);
points-> addObject (pt3);

/* insert between the first two */
points-> insertObject (pt2, 1);

Since a call to insertObject() without an index appends to the end of the aggregate, all of the following calls are equivalent:

points-> addObject (pt1);
points-> insertObject (pt1);
points-> insertObject (pt1, points-> size());
points-> putObject (pt1, points-> size());

See Also

RoseObject::put<type>()

last()

<type_ref> last();

The last() function returns the last element of an aggregate. If the aggregate is empty, the function returns the null value for the type. This function is defined by each parameterized aggregate class.

The following example prints the last element from a list of strings.

ListOfString * strings;

printf (The last string is %s\n, strings-> last());
printf (The last string is %s\n, strings-> get(strings-> size()-1));

put()

<class_name> * put(
	<type_ref> newValue,
	unsigned index
	);

The put() function replaces the value at a given index. If the index is beyond the end of the aggregate, the value will be appended. The aggregate is expanded by one element regardless of whether the index is five places beyond the end or five thousand. Aggregates are indexed beginning at zero. This function is defined by each parameterized aggregate class.

The following example creates an aggregate of strings and then replaces some of the values using the put() function.

ListOfString * strings = new ListOfString;

strings->add (string zero);
strings->add (string one);
strings->add (string two);

strings->put (new string two, 2);

/* the following are both equivalent to the add() function */
strings->put (string three, 3);
strings->put (string four, 50);

The last put() still only appends the value, despite the large index.

See Also

RoseAggregate::add(); RoseAggregate::insert()

removeAt()

void removeAt(
	unsigned index
	);

The removeAt() function removes the element at the specified index. This function has no effect if the index is out of bounds. Aggregates are indexed beginning at zero. The size of the aggregate is reduced by one.

The following example creates a small list and then uses the removeAt() function to eliminate some elements from it.

ListOfString * strings = new ListOfString;

strings->add (string zero);
strings->add (string one);
strings->add (string two);

strings->removeAt (1);   /* removes string one */
strings->removeAt (1);   /* list has shrunk, removes string two */

See Also

emptyYourself(); RoseAggregate::find(); RoseAggregate::removeValue()

removeValue()

void removeValue(
	<type_ref> target
	);

The removeValue() function searches for, and removes, any aggregate elements which match the target value. The size of the aggregate will be reduced by however many elements are removed. The function uses find() to look for values. This function is defined by each parameterized aggregate class.

The following example creates a small list and then uses the removeValue() function to remove some elements from it.

ListOfString * strings = new ListOfString;

strings->add (string zero);
strings->add (string one);
strings->add (string one);
strings->add (string two);

strings->removeValue (string one);   /* removes elements 1 and 2 */

The following code segment is less efficient than but otherwise functionally equivalent to the removeValue() operation.

while (strings-> contain (string one))
     strings-> removeAt (strings-> find (string one));

See Also

emptyYourself(); RoseAggregate::find(); RoseAggregate::removeAt()

size() (change size)

virtual void size(
	unsigned new_size,
	int starting_index = -1
	);

The size() function expands or contracts the size of an array. The function takes the new size and an optional insertion position. If an insertion index is given, elements are inserted or deleted from this point, otherwise they are added or removed from the end. Aggregates are indexed beginning at zero.

This function is only defined by RoseArray subtypes. The RoseObject class defines an access function that returns the size of an aggregate. See RoseObject::size() for details.

The following example creates an array of strings with five elements and then shrinks the array to three elements.

ArrayOfString * strings = new ArrayOfString (5);

strings->put (string zero,  0);
strings->put (string one,   1);
strings->put (string two,   2);
strings->put (string three, 3);
strings->put (string four,  4);

/* resize the array starting at element 2 */
strings-> size (3, 2)

The resulting array should contain strings zero, one, and four. Consider the following:

    /* resize the array starting at the end */
    strings-> size (3)

The resize would occur from the end of the array and the resulting array would contain strings zero, one, and two.

See Also

RoseAggregate Constructor; capacity()