/*-----------------------------------------------------------------------------+ Copyright (c) 2008-2010: Joachim Faulhaber +------------------------------------------------------------------------------+ Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENCE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +-----------------------------------------------------------------------------*/ #ifndef BOOST_ICL_INTERVAL_SET_ALGO_HPP_JOFA_081005 #define BOOST_ICL_INTERVAL_SET_ALGO_HPP_JOFA_081005 #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost{namespace icl { namespace Interval_Set { //------------------------------------------------------------------------------ // Lexicographical comparison on ranges of two interval container //------------------------------------------------------------------------------ template bool is_element_equal(const LeftT& left, const RightT& right) { return subset_compare ( left, right, left.begin(), left.end(), right.begin(), right.end() ) == inclusion::equal; } template bool is_element_less(const LeftT& left, const RightT& right) { return element_compare ( left, right, left.begin(), left.end(), right.begin(), right.end() ) == comparison::less; } template bool is_element_greater(const LeftT& left, const RightT& right) { return element_compare ( left, right, left.begin(), left.end(), right.begin(), right.end() ) == comparison::greater; } //------------------------------------------------------------------------------ // Subset/superset compare on ranges of two interval container //------------------------------------------------------------------------------ template bool is_joinable(const IntervalContainerT& container, typename IntervalContainerT::const_iterator first, typename IntervalContainerT::const_iterator past) { if(first == container.end()) return true; typename IntervalContainerT::const_iterator it_ = first, next_ = first; ++next_; while(next_ != container.end() && it_ != past) if(!icl::touches(key_value(it_++), key_value(next_++))) return false; return true; } template bool is_inclusion_equal(const LeftT& left, const RightT& right) { return subset_compare ( left, right, left.begin(), left.end(), right.begin(), right.end() ) == inclusion::equal; } template typename enable_if, is_total >, bool>::type within(const LeftT&, const RightT&) { return true; } template typename enable_if, mpl::not_ > >, bool>::type within(const LeftT& sub, const RightT& super) { int result = subset_compare ( sub, super, sub.begin(), sub.end(), super.begin(), super.end() ); return result == inclusion::subset || result == inclusion::equal; } template typename enable_if, bool>::type within(const LeftT& sub, const RightT& super) { int result = subset_compare ( sub, super, sub.begin(), sub.end(), super.begin(), super.end() ); return result == inclusion::subset || result == inclusion::equal; } template typename enable_if, bool>::type within(const LeftT& sub, const RightT& super) { int result = subset_compare ( sub, super, sub.begin(), sub.end(), super.begin(), super.end() ); return result == inclusion::subset || result == inclusion::equal; } template typename enable_if, is_total >, bool>::type contains(const LeftT&, const RightT&) { return true; } template typename enable_if, mpl::not_ > >, bool>::type contains(const LeftT& super, const RightT& sub) { int result = subset_compare ( super, sub, super.begin(), super.end(), sub.begin(), sub.end() ); return result == inclusion::superset || result == inclusion::equal; } template typename enable_if, bool>::type contains(const LeftT& super, const RightT& sub) { int result = subset_compare ( super, sub, super.begin(), super.end(), sub.begin(), sub.end() ); return result == inclusion::superset || result == inclusion::equal; } template bool is_dense(const IntervalContainerT& container, typename IntervalContainerT::const_iterator first, typename IntervalContainerT::const_iterator past) { if(first == container.end()) return true; typename IntervalContainerT::const_iterator it_ = first, next_ = first; ++next_; while(next_ != container.end() && it_ != past) if(!icl::touches(key_value(it_++), key_value(next_++))) return false; return true; } } // namespace Interval_Set namespace segmental { template inline bool joinable(const Type& _Type, typename Type::iterator& some, typename Type::iterator& next) { // assert: next != end && some++ == next return touches(key_value(some), key_value(next)) && co_equal(some, next, &_Type, &_Type); } template inline void join_nodes(Type& object, typename Type::iterator& left_, typename Type::iterator& right_) { typedef typename Type::interval_type interval_type; interval_type right_interval = key_value(right_); object.erase(right_); const_cast(key_value(left_)) = hull(key_value(left_), right_interval); } template inline typename Type::iterator join_on_left(Type& object, typename Type::iterator& left_, typename Type::iterator& right_) { //CL typedef typename Type::interval_type interval_type; // both left and right are in the set and they are neighbours BOOST_ASSERT(exclusive_less(key_value(left_), key_value(right_))); BOOST_ASSERT(joinable(object, left_, right_)); join_nodes(object, left_, right_); return left_; } template inline typename Type::iterator join_on_right(Type& object, typename Type::iterator& left_, typename Type::iterator& right_) { //CL typedef typename Type::interval_type interval_type; // both left and right are in the map and they are neighbours BOOST_ASSERT(exclusive_less(key_value(left_), key_value(right_))); BOOST_ASSERT(joinable(object, left_, right_)); join_nodes(object, left_, right_); right_ = left_; return right_; } template typename Type::iterator join_left(Type& object, typename Type::iterator& it_) { typedef typename Type::iterator iterator; if(it_ == object.begin()) return it_; // there is a predecessor iterator pred_ = it_; if(joinable(object, --pred_, it_)) return join_on_right(object, pred_, it_); return it_; } template typename Type::iterator join_right(Type& object, typename Type::iterator& it_) { typedef typename Type::iterator iterator; if(it_ == object.end()) return it_; // there is a successor iterator succ_ = it_; if(++succ_ != object.end() && joinable(object, it_, succ_)) return join_on_left(object, it_, succ_); return it_; } template typename Type::iterator join_neighbours(Type& object, typename Type::iterator& it_) { join_left (object, it_); return join_right(object, it_); } template inline typename Type::iterator join_under(Type& object, const typename Type::value_type& addend) { //ASSERT: There is at least one interval in object that overlaps with addend typedef typename Type::iterator iterator; typedef typename Type::interval_type interval_type; typedef typename Type::value_type value_type; std::pair overlap = object.equal_range(addend); iterator first_ = overlap.first, end_ = overlap.second, last_ = end_; --last_; iterator second_= first_; ++second_; interval_type left_resid = right_subtract(key_value(first_), addend); interval_type right_resid = left_subtract(key_value(last_) , addend); object.erase(second_, end_); const_cast(key_value(first_)) = hull(hull(left_resid, addend), right_resid); return first_; } template inline typename Type::iterator join_under(Type& object, const typename Type::value_type& addend, typename Type::iterator last_) { //ASSERT: There is at least one interval in object that overlaps with addend typedef typename Type::iterator iterator; typedef typename Type::interval_type interval_type; typedef typename Type::value_type value_type; iterator first_ = object.lower_bound(addend); //BOOST_ASSERT(next(last_) == this->_set.upper_bound(inter_val)); iterator second_= boost::next(first_), end_ = boost::next(last_); interval_type left_resid = right_subtract(key_value(first_), addend); interval_type right_resid = left_subtract(key_value(last_) , addend); object.erase(second_, end_); const_cast(key_value(first_)) = hull(hull(left_resid, addend), right_resid); return first_; } } // namespace segmental namespace Interval_Set { using namespace segmental; template struct on_style; template struct on_style { typedef on_style type; typedef typename Type::interval_type interval_type; typedef typename Type::iterator iterator; inline static iterator handle_inserted(Type& object, iterator inserted_) { return join_neighbours(object, inserted_); } inline static iterator add_over (Type& object, const interval_type& addend, iterator last_) { iterator joined_ = join_under(object, addend, last_); return join_neighbours(object, joined_); } inline static iterator add_over (Type& object, const interval_type& addend) { iterator joined_ = join_under(object, addend); return join_neighbours(object, joined_); } }; template struct on_style { typedef on_style type; typedef typename Type::interval_type interval_type; typedef typename Type::iterator iterator; inline static iterator handle_inserted(Type&, iterator inserted_) { return inserted_; } inline static iterator add_over (Type& object, const interval_type& addend, iterator last_) { return join_under(object, addend, last_); } inline static iterator add_over (Type& object, const interval_type& addend) { return join_under(object, addend); } }; template struct on_style { typedef on_style type; typedef typename Type::interval_type interval_type; typedef typename Type::iterator iterator; inline static iterator handle_inserted(Type&, iterator inserted_) { return inserted_; } inline static iterator add_over (Type& object, const interval_type& addend, iterator last_) { iterator first_ = object.lower_bound(addend); //BOOST_ASSERT(next(last_) == this->_set.upper_bound(inter_val)); iterator it_ = first_; interval_type rest_interval = addend; add_front(object, rest_interval, it_); add_main (object, rest_interval, it_, last_); add_rear (object, rest_interval, it_); return it_; } inline static iterator add_over (Type& object, const interval_type& addend) { std::pair overlap = object.equal_range(addend); iterator first_ = overlap.first, end_ = overlap.second, last_ = end_; --last_; iterator it_ = first_; interval_type rest_interval = addend; add_front(object, rest_interval, it_); add_main (object, rest_interval, it_, last_); add_rear (object, rest_interval, it_); return it_; } }; template void add_front(Type& object, const typename Type::interval_type& inter_val, typename Type::iterator& first_) { typedef typename Type::interval_type interval_type; typedef typename Type::iterator iterator; // If the collision sequence has a left residual 'left_resid' it will // be split, to provide a standardized start of algorithms: // The addend interval 'inter_val' covers the beginning of the collision sequence. // only for the first there can be a left_resid: a part of *first_ left of inter_val interval_type left_resid = right_subtract(key_value(first_), inter_val); if(!icl::is_empty(left_resid)) { // [------------ . . . // [left_resid---first_ --- . . . iterator prior_ = cyclic_prior(object, first_); const_cast(key_value(first_)) = left_subtract(key_value(first_), left_resid); //NOTE: Only splitting object._insert(prior_, icl::make_value(left_resid, co_value(first_))); } //POST: // [----- inter_val ---- . . . // ...[-- first_ --... } template void add_segment(Type& object, const typename Type::interval_type& inter_val, typename Type::iterator& it_ ) { typedef typename Type::interval_type interval_type; interval_type lead_gap = right_subtract(inter_val, *it_); if(!icl::is_empty(lead_gap)) // [lead_gap--- . . . // [prior_) [-- it_ ... object._insert(prior(it_), lead_gap); // . . . --------- . . . addend interval // [-- it_ --) has a common part with the first overval ++it_; } template void add_main(Type& object, typename Type::interval_type& rest_interval, typename Type::iterator& it_, const typename Type::iterator& last_) { typedef typename Type::interval_type interval_type; interval_type cur_interval; while(it_ != last_) { cur_interval = *it_ ; add_segment(object, rest_interval, it_); // shrink interval rest_interval = left_subtract(rest_interval, cur_interval); } } template void add_rear(Type& object, const typename Type::interval_type& inter_val, typename Type::iterator& it_ ) { typedef typename Type::interval_type interval_type; typedef typename Type::iterator iterator; iterator prior_ = cyclic_prior(object, it_); interval_type cur_itv = *it_; interval_type lead_gap = right_subtract(inter_val, cur_itv); if(!icl::is_empty(lead_gap)) // [lead_gap--- . . . // [prior_) [-- it_ ... object._insert(prior_, lead_gap); interval_type end_gap = left_subtract(inter_val, cur_itv); if(!icl::is_empty(end_gap)) // [---------------end_gap) // [-- it_ --) it_ = object._insert(it_, end_gap); else { // only for the last there can be a right_resid: a part of *it_ right of addend interval_type right_resid = left_subtract(cur_itv, inter_val); if(!icl::is_empty(right_resid)) { // [--------------) // [-- it_ --right_resid) const_cast(*it_) = right_subtract(*it_, right_resid); it_ = object._insert(it_, right_resid); } } } //============================================================================== //= Addition //============================================================================== template typename Type::iterator add(Type& object, const typename Type::value_type& addend) { //CL typedef typename Type::interval_type interval_type; typedef typename Type::iterator iterator; typedef typename on_style::type on_style_; if(icl::is_empty(addend)) return object.end(); std::pair insertion = object._insert(addend); if(insertion.second) return on_style_::handle_inserted(object, insertion.first); else return on_style_::add_over(object, addend, insertion.first); } template typename Type::iterator add(Type& object, typename Type::iterator prior_, const typename Type::value_type& addend) { //CL typedef typename Type::interval_type interval_type; typedef typename Type::iterator iterator; typedef typename on_style::type on_style_; if(icl::is_empty(addend)) return prior_; iterator insertion = object._insert(prior_, addend); if(*insertion == addend) return on_style_::handle_inserted(object, insertion); else return on_style_::add_over(object, addend); } //============================================================================== //= Subtraction //============================================================================== template void subtract(Type& object, const typename Type::value_type& minuend) { typedef typename Type::iterator iterator; typedef typename Type::interval_type interval_type; //CL typedef typename Type::value_type value_type; if(icl::is_empty(minuend)) return; std::pair exterior = object.equal_range(minuend); if(exterior.first == exterior.second) return; iterator first_ = exterior.first; iterator end_ = exterior.second; iterator last_ = end_; --last_; interval_type leftResid = right_subtract(*first_, minuend); interval_type rightResid; if(first_ != end_ ) rightResid = left_subtract(*last_ , minuend); object.erase(first_, end_); if(!icl::is_empty(leftResid)) object._insert(leftResid); if(!icl::is_empty(rightResid)) object._insert(rightResid); } } // namespace Interval_Set }} // namespace icl boost #endif