...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Instead of writing loops, the standard algorithm std::transform
can be used to fill interval containers from std containers of user defined
objects. We need a function, that maps the user defined object
into the segement type of an interval map or the interval
type of an interval set. Based on that we can use std::transform
with an icl::inserter
or icl::adder
to transform the user objects into interval containers.
#include <iostream> #include <vector> #include <algorithm> #include <boost/icl/split_interval_map.hpp> #include <boost/icl/separate_interval_set.hpp> using namespace std; using namespace boost; using namespace boost::icl; // Suppose we are working with a class called MyObject, containing some // information about interval bounds e.g. _from, _to and some data members // that carry associated information like e.g. _value. class MyObject { public: MyObject(){} MyObject(int from, int to, int value): _from(from), _to(to), _value(value){} int from()const {return _from;} int to()const {return _to;} int value()const{return _value;} private: int _from; int _to; int _value; }; // ... in order to use the std::transform algorithm to fill // interval maps with MyObject data we need a function // 'to_segment' that maps an object of type MyObject into // the value type to the interval map we want to tranform to ... pair<discrete_interval<int>, int> to_segment(const MyObject& myObj) { return std::pair< discrete_interval<int>, int > (discrete_interval<int>::closed(myObj.from(), myObj.to()), myObj.value()); } // ... there may be another function that returns the interval // of an object only discrete_interval<int> to_interval(const MyObject& myObj) { return discrete_interval<int>::closed(myObj.from(), myObj.to()); } // ... make_object computes a sequence of objects to test. vector<MyObject> make_objects() { vector<MyObject> object_vec; object_vec.push_back(MyObject(2,3,1)); object_vec.push_back(MyObject(4,4,1)); object_vec.push_back(MyObject(1,2,1)); return object_vec; } // ... show_objects displays the sequence of input objects. void show_objects(const vector<MyObject>& objects) { vector<MyObject>::const_iterator iter = objects.begin(); while(iter != objects.end()) { cout << "([" << iter->from() << "," << iter->to() << "]," << iter->value() << ")"; ++iter; } } void std_transform() { // This time we want to transform objects into a splitting interval map: split_interval_map<int,int> segmap; vector<MyObject> myObjects = make_objects(); // Display the input cout << "input sequence: "; show_objects(myObjects); cout << "\n\n"; // Use an icl::inserter to fill the interval map via inserts std::transform(myObjects.begin(), myObjects.end(), icl::inserter(segmap, segmap.end()), to_segment); cout << "icl::inserting: " << segmap << endl; segmap.clear(); // In order to compute aggregation results on associated values, we // usually want to use an icl::adder instead of an std or icl::inserter std::transform(myObjects.begin(), myObjects.end(), icl::adder(segmap, segmap.end()), to_segment); cout << "icl::adding : " << segmap << "\n\n"; separate_interval_set<int> segset; std::transform(myObjects.begin(), myObjects.end(), icl::adder (segset, segset.end()), // could be a icl::inserter(segset, segset.end()), here: same effect to_interval); cout << "Using std::transform to fill a separate_interval_set:\n\n"; cout << "icl::adding : " << segset << "\n\n"; } int main() { cout << ">> Interval Container Library: Example std_transform.cpp <<\n"; cout << "------------------------------------------------------------\n"; cout << "Using std::transform to fill a split_interval_map:\n\n"; std_transform(); return 0; } // Program output: /*---------------------------------------------------------- >> Interval Container Library: Example std_transform.cpp << ------------------------------------------------------------ Using std::transform to fill a split_interval_map: input sequence: ([2,3],1)([4,4],1)([1,2],1) icl::inserting: {([1,2)->1)([2,3]->1)([4,4]->1)} icl::adding : {([1,2)->1)([2,2]->2)((2,3]->1)([4,4]->1)} Using std::transform to fill a separate_interval_set: icl::adding : {[1,3][4,4]} ----------------------------------------------------------*/
To get clear about the different behaviors of interval containers in the example, you may want to refer to the section about interval combining styles that uses the same data.