Using Containers
This chapter will describe the use of containers with the Flip framework.
In the following, we will show the step by step construction of an hypothetic MyClass class.
This chapter will assume that your company is called ACME making the application “Product”.
Which Container to Use ?
The Flip framework offers two type of container. The first one, ohm::flip::Array is an explicitely ordered container. The second one, ohm::flip::Collection is either an implicitely ordered container or an unordered container.
The containers themselves can hold any flip classes, except basic classes offered by Flip. They support inheritance, so that if MySubClass1 and MySubClass2 inherit from MyClass a container of MyClass will support indifferently MySubClass1 or MySubClass2 .
An explicitely ordered container is defined as an ordered container in which the client of the container decides of the order of the elements in the container. Typically, this is similar to the std::list or std::vector template classes, in which the client has full control over the order of the elements in the container.
An implicitely ordered container is defined as an ordered container in which the order of elements is implicitely defined by the elements themselves, that is there exists a total order (as opposed to partial order) for the elements. Typically, this is similar to the std::set template class for which the compound element must support operator < . Flip classes in the implicitely ordered container must support the operator < as well. Total order condition can always be met, and this will be exposed in the code below.
Container choice algorithm is summarized in the diagram below :

Containers actually owns their elements. In particular, if a container is destroyed, its elements will be automatically destroyed.
The following code with only show the ext_ prefixed version of the functions as this is the only one that will directly manipulate the containers. The other functions are anyway exactly the same since they never directly manipulate the model itself, but only manages transaction life cycles.
Using Arrays
The following listing shows a MyClass class containing elements of the MyElementClass class. The code was trimmed down to show only the interesting parts.
As a convention, all arrays of a particular class are turned into a typedef to clean up the code. As you will make massive use of iterators, this keeps the code a lot more easier to read.
ListingMyElementClassArr.h
typedef ohm::flip::Array <MyElementClass> MyElementClassArr; |
ListingMyClass.h
#include "ohm/flip/Object.h" |
class MyClass |
: public ohm::flip::Object |
{ |
public: |
static void declare (); |
MyClass (ohm::flip::DocumentBase & document); |
virtual ~MyClass () {} |
MyElementClassArr::iterator |
ext_push_back_element (); |
void ext_erase (MyElementClassArr::iterator it) |
private: |
MyElementClassArr _my_element_class_arr; |
}; |
ListingMyClass::ext_push_back_element
MyElementClassArr::iterator MyClass::ext_push_back_element () |
{ |
return _my_element_class_arr.insert (_my_element_class_arr.end ()); |
} |
The code above will add an element of class MyElementClass to the array _my_element_class_arr .
Similarly, you may erase an element with the following code
ListingMyClass::ext_erase
void MyClass::ext_erase (MyElementClassArr::iterator it) |
{ |
_my_element_class_arr.erase (it); |
} |
Using Collections
The following listing shows a MyClass class containing elements of the MyElementClass class. The code was trimmed down to show only the interesting parts.
As a convention, all collections of a particular class are turned into a typedef to clean up the code. As you will make massive use of iterators, this keeps the code a lot more easier to read.
ListingMyElementClassColl.h
typedef ohm::flip::Collection <MyElementClass> MyElementClassColl; |
ListingMyClass.h
#include "ohm/flip/Object.h" |
class MyClass |
: public ohm::flip::Object |
{ |
public: |
static void declare (); |
MyClass (ohm::flip::DocumentBase & document); |
virtual ~MyClass () {} |
MyElementClassColl::iterator |
ext_insert_element (); |
void ext_erase (MyElementClassColl::iterator it) |
private: |
MyElementClassColl _my_element_class_coll; |
}; |
ListingMyClass::ext_insert_element
MyElementClassColl::iterator MyClass::ext_insert_element () |
{ |
return _my_element_class_coll.insert (); |
} |
The code above will add an element of class MyElementClass to the collection _my_element_class_coll .
Similarly, you may erase an element with the following code
ListingMyClass::ext_erase
void MyClass::ext_erase (MyElementClassColl::iterator it) |
{ |
_my_element_class_coll.erase (it); |
} |
The code above wouldn’t work if MyElementClass does not support operator < . The next section will show how to write this operator, and in particular to provide a total order operator.
Writing Collection Element Comparison Operator
Whenever a collection is used as an unordered container or an implicitely ordered container, the collection element needs to support operator < which needs to provide a total order, that is if a < b is a false assertion and b < a is a false assertion, then a == b .
We are going to see here how to write those comparators in the two cases.
Unordered Container
The total order condition requires that we are able to make a distinction between two different objects. This can be easily achieved using the objet reference number, which is guaranteed to be unique.
Therefore, such a comparison operator would be written like this :
bool MyElementClass::operator < (const MyElementClass & other) |
{ |
return get_ref () < other.get_ref (); |
} |
Implicitely Ordered Container
The total order condition requires that we are able to make a distinction between two different objects.
For the example, we suppose that the MyElementClass class has a ohm::flip::Float64 _position class member, and that we want the collection to be ordered by position.
Such a comparison operator would be written like this :
#include "ohm/lang/fnc.h" |
bool MyElementClass::operator < (const MyElementClass & other) |
{ |
int c = lang::cmp (get_position (), other.get_position ()); |
if (c != 0) return c < 0; |
c = lang::cmp (get_ref (), other.other.get_ref ()); |
return c < 0; |
} |
Note that total order is achieved by using the objet reference number, which is guaranteed to be unique.
Inheritance
The containers support inheritance, so that if MySubElementClass1 and MySubElementClass2 inherit from MyElementClass a container of MyElementClass will support indifferently MySubElementClass1 or MySubElementClass2 .
To insert a MySubElementClass1 into a MyElementClass container, the code would be written like this for an array :
_my_element_class_arr.insert <MySubElementClass1> (it); |
And the code would be writtent like this for a collection :
_my_element_class_coll.insert <MySubElementClass1> (); |