Boost.ICL's interval_map has two kinds of behaviors: += and insert.
Both are useful in different context.
The first adds up values in common intersections of two existing intervals.
The second simply introduces the new value only in previously unassigned intervals (in previously assigned intervals the value is kept).
However I need a behavior that is subtly different, such that, in the example below instead of getting the undesired interval map (1.,2.)->1 , (2.5,3.)->3, (3.,5.)->2 I get instead the desired (1.,2.)->1 , (2.5,5.)->3.
That is, that new inserted values replace old values?
How do I declare interval_map to get that replacing behavior?
#include<boost/icl/interval_map.hpp>
int main(){
boost::icl::interval_map<double, int> joined_map;
joined_map.insert( std::make_pair(
boost::icl::interval<double>::open(1., 2.),
1
));
joined_map.insert( std::make_pair(
boost::icl::interval<double>::open(3., 5.),
2
));
joined_map.insert( std::make_pair(
boost::icl::interval<double>::open(2.5, 5.),
3
)); // this line doesn't replace the old value 2, it keeps it.
}
Bonus: Is that what boost::icl::map is supposed to do? How do I use it?
EDIT 1: This is a more explicit and simplified sample code using C++11
#include<boost/icl/interval_map.hpp>
#include<iostream>
namespace icl = boost::icl;
using interval = icl::interval<double>;
int main(){
icl::interval_map<double, int> joined_map;
joined_map.insert({interval::open(1., 2.), 1});
joined_map.insert({interval::open(3., 5.), 2});
joined_map.insert({interval::open(2.5, 5.), 3});
// ^^^^ this line doesn't replace the old value 2! it keeps it.
for(auto e: joined_map) std::cout << e.first <<' '<< e.second <<'\n';
// prints: (1,2) 1 \\ (2.5,3] 3 \\ (3,5) 2
// desired: (1,2) 1 \\ (2.5,5] 3 // value 2 gone
}
EDIT 2: Complete solution based on @JorgeBellon's answer:
#include<boost/icl/interval_map.hpp>
#include<iostream>
namespace icl = boost::icl;
template <class Type>
struct inplace_replace{// : icl::identity_based_inplace_combine<Type>{
using first_argument_type = Type;
void operator()(Type& object, Type const& operand) const{object = operand;}
};
using interval = icl::interval<double>;
int main(){
icl::interval_map<
double, int,
icl::partial_enricher, // Unmapped intervals have unkown value;
// store identity values
std::less , // Comparator
inplace_replace //, // Combination operator // IMPORTANT!!
// icl::inplace_erasure//, // Extraction operator
// closed_interval<unsigned, std::less> // Interval type
> joined_map;
joined_map.add({interval::open(1. , 2.), 1}); // or joined_map+=std::make_pair(...)
joined_map.add({interval::open(3. , 5.), 2}); // IMPORTANT: USE add, NOT insert!!
joined_map.add({interval::open(2.5, 5.), 3});
// ^^^^ this line now replaces the old value 2
for(auto e: joined_map) std::cout << e.first <<' '<< e.second <<'\n';
// prints: (1,2) 1 \\ (2.5,5] 3 // value 2 gone
}
One of the interval map's template parameters is the combination operator type. The typical example consists on map using
std::setor similar as a value and then it uses the addition or the identity (keep the existing value) as operations.Since the overwrite example is not there by default, you can create yours and pass it to the map yourself:
See complete example: https://ideone.com/C49bDM
Edit: deriving from
identity_based_inplace_combine<Type>(boost/icl/functors.hpp) does the following:first_argument_type,second_argument_typeandresult_type.identity_elementvalue for that type (a static function). For example the identity value for a set is an empty set, for an integer it is0(useful when you do a sum), etc.It is not mandatory to use it if your map is
partial_enricherortotal_enricher, since in this case the map will contain entries for any values, including identity values. You will need it for theabsorbertypes, since the map needs to know whether it can drop the interval or not in that case.An alternative:
Note: older boost ICL implementations derive from
std::binary_functioninstead of using these typedefs. Unfortunately this is deprecated in C++11 and removed in C++17, so I would try not to use it in your own code. The latest versions implement the functors like the snippet above.Same example: https://ideone.com/lMLEDw