// (C) Copyright Jeremy Siek 2004 // (C) Copyright Thomas Claveirole 2010 // (C) Copyright Ignacy Gawedzki 2010 // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_DETAIL_CONTAINER_TRAITS_H #define BOOST_GRAPH_DETAIL_CONTAINER_TRAITS_H // Sure would be nice to be able to forward declare these // instead of pulling in all the headers. Too bad that // is not legal. There ought to be a standard header. -JGS #include #include // for std::remove #include #include #include #include #include #include #if !defined BOOST_NO_SLIST # ifdef BOOST_SLIST_HEADER # include BOOST_SLIST_HEADER # else # include # endif #endif #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) // Stay out of the way of concept checking class templates # define Container Container_ # define AssociativeContainer AssociativeContainer_ #endif // The content of this file is in 'graph_detail' because otherwise // there will be name clashes with // sandbox/boost/sequence_algo/container_traits.hpp // The 'detail' subnamespace will still cause problems. namespace boost { namespace graph_detail { //====================================================================== // Container Category Tags // // They use virtual inheritance because there are lots of // inheritance diamonds. struct container_tag { }; struct forward_container_tag : virtual public container_tag { }; struct reversible_container_tag : virtual public forward_container_tag { }; struct random_access_container_tag : virtual public reversible_container_tag { }; struct sequence_tag : virtual public forward_container_tag { }; struct associative_container_tag : virtual public forward_container_tag { }; struct sorted_associative_container_tag : virtual public associative_container_tag, virtual public reversible_container_tag { }; struct front_insertion_sequence_tag : virtual public sequence_tag { }; struct back_insertion_sequence_tag : virtual public sequence_tag { }; struct unique_associative_container_tag : virtual public associative_container_tag { }; struct multiple_associative_container_tag : virtual public associative_container_tag { }; struct simple_associative_container_tag : virtual public associative_container_tag { }; struct pair_associative_container_tag : virtual public associative_container_tag { }; //====================================================================== // Iterator Stability Tags // // Do mutating operations such as insert/erase/resize invalidate all // outstanding iterators? struct stable_tag { }; struct unstable_tag { }; //====================================================================== // Container Traits Class and container_category() function #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // don't use this unless there is partial specialization template struct container_traits { typedef typename Container::category category; typedef typename Container::iterator_stability iterator_stability; }; #endif // Use this as a compile-time assertion that X is stable inline void require_stable(stable_tag) { } // std::vector struct vector_tag : virtual public random_access_container_tag, virtual public back_insertion_sequence_tag { }; template vector_tag container_category(const std::vector&) { return vector_tag(); } template unstable_tag iterator_stability(const std::vector&) { return unstable_tag(); } #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct container_traits< std::vector > { typedef vector_tag category; typedef unstable_tag iterator_stability; }; #endif // std::list struct list_tag : virtual public reversible_container_tag, virtual public back_insertion_sequence_tag // this causes problems for push_dispatch... // virtual public front_insertion_sequence_tag { }; template list_tag container_category(const std::list&) { return list_tag(); } template stable_tag iterator_stability(const std::list&) { return stable_tag(); } #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct container_traits< std::list > { typedef list_tag category; typedef stable_tag iterator_stability; }; #endif // std::slist #ifndef BOOST_NO_SLIST # ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct container_traits > { typedef front_insertion_sequence_tag category; typedef stable_tag iterator_stability; }; #endif template front_insertion_sequence_tag container_category( const BOOST_STD_EXTENSION_NAMESPACE::slist& ) { return front_insertion_sequence_tag(); } template stable_tag iterator_stability( const BOOST_STD_EXTENSION_NAMESPACE::slist&) { return stable_tag(); } #endif // std::set struct set_tag : virtual public sorted_associative_container_tag, virtual public simple_associative_container_tag, virtual public unique_associative_container_tag { }; template set_tag container_category(const std::set&) { return set_tag(); } template stable_tag iterator_stability(const std::set&) { return stable_tag(); } #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct container_traits< std::set > { typedef set_tag category; typedef stable_tag iterator_stability; }; #endif // std::multiset struct multiset_tag : virtual public sorted_associative_container_tag, virtual public simple_associative_container_tag, virtual public multiple_associative_container_tag { }; template multiset_tag container_category(const std::multiset&) { return multiset_tag(); } template stable_tag iterator_stability(const std::multiset&) { return stable_tag(); } #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct container_traits< std::multiset > { typedef multiset_tag category; typedef stable_tag iterator_stability; }; #endif // deque // std::map struct map_tag : virtual public sorted_associative_container_tag, virtual public pair_associative_container_tag, virtual public unique_associative_container_tag { }; #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct container_traits< std::map > { typedef map_tag category; typedef stable_tag iterator_stability; }; #endif template map_tag container_category(const std::map&) { return map_tag(); } template stable_tag iterator_stability(const std::map&) { return stable_tag(); } // std::multimap struct multimap_tag : virtual public sorted_associative_container_tag, virtual public pair_associative_container_tag, virtual public multiple_associative_container_tag { }; #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct container_traits< std::multimap > { typedef multimap_tag category; typedef stable_tag iterator_stability; }; #endif template multimap_tag container_category(const std::multimap&) { return multimap_tag(); } template stable_tag iterator_stability(const std::multimap&) { return stable_tag(); } // hash_set, hash_map struct unordered_set_tag : virtual public simple_associative_container_tag, virtual public unique_associative_container_tag { }; struct unordered_multiset_tag : virtual public simple_associative_container_tag, virtual public multiple_associative_container_tag { }; struct unordered_map_tag : virtual public pair_associative_container_tag, virtual public unique_associative_container_tag { }; struct unordered_multimap_tag : virtual public pair_associative_container_tag, virtual public multiple_associative_container_tag { }; #ifndef BOOST_NO_HASH #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct container_traits< boost::unordered_set > { typedef unordered_set_tag category; typedef unstable_tag iterator_stability; }; template struct container_traits< boost::unordered_map > { typedef unordered_map_tag category; typedef unstable_tag iterator_stability; }; template struct container_traits< boost::unordered_multiset > { typedef unordered_multiset_tag category; typedef unstable_tag iterator_stability; }; template struct container_traits< boost::unordered_multimap > { typedef unordered_multimap_tag category; typedef unstable_tag iterator_stability; }; #endif template unordered_set_tag container_category(const boost::unordered_set&) { return unordered_set_tag(); } template unordered_map_tag container_category(const boost::unordered_map&) { return unordered_map_tag(); } template unstable_tag iterator_stability(const boost::unordered_set&) { return unstable_tag(); } template unstable_tag iterator_stability(const boost::unordered_map&) { return unstable_tag(); } template unordered_multiset_tag container_category(const boost::unordered_multiset&) { return unordered_multiset_tag(); } template unordered_multimap_tag container_category(const boost::unordered_multimap&) { return unordered_multimap_tag(); } template unstable_tag iterator_stability(const boost::unordered_multiset&) { return unstable_tag(); } template unstable_tag iterator_stability(const boost::unordered_multimap&) { return unstable_tag(); } #endif //=========================================================================== // Generalized Container Functions // Erase template void erase_dispatch(Sequence& c, const T& x, sequence_tag) { c.erase(std::remove(c.begin(), c.end(), x), c.end()); } template void erase_dispatch(AssociativeContainer& c, const T& x, associative_container_tag) { c.erase(x); } template void erase(Container& c, const T& x) { erase_dispatch(c, x, container_category(c)); } // Erase If template void erase_if_dispatch(Sequence& c, Predicate p, sequence_tag, IteratorStability) { #if 0 c.erase(std::remove_if(c.begin(), c.end(), p), c.end()); #else if (! c.empty()) c.erase(std::remove_if(c.begin(), c.end(), p), c.end()); #endif } template void erase_if_dispatch(AssociativeContainer& c, Predicate p, associative_container_tag, stable_tag) { typename AssociativeContainer::iterator i, next; for (i = next = c.begin(); next != c.end(); i = next) { ++next; if (p(*i)) c.erase(i); } } template void erase_if_dispatch(AssociativeContainer& c, Predicate p, associative_container_tag, unstable_tag) { // This method is really slow, so hopefully we won't have any // associative containers with unstable iterators! // Is there a better way to do this? typename AssociativeContainer::iterator i; typename AssociativeContainer::size_type n = c.size(); while (n--) for (i = c.begin(); i != c.end(); ++i) if (p(*i)) { c.erase(i); break; } } template void erase_if(Container& c, Predicate p) { erase_if_dispatch(c, p, container_category(c), iterator_stability(c)); } // Push template std::pair push_dispatch(Container& c, const T& v, back_insertion_sequence_tag) { c.push_back(v); return std::make_pair(boost::prior(c.end()), true); } template std::pair push_dispatch(Container& c, const T& v, front_insertion_sequence_tag) { c.push_front(v); return std::make_pair(c.begin(), true); } template std::pair push_dispatch(AssociativeContainer& c, const T& v, unique_associative_container_tag) { return c.insert(v); } template std::pair push_dispatch(AssociativeContainer& c, const T& v, multiple_associative_container_tag) { return std::make_pair(c.insert(v), true); } template std::pair push(Container& c, const T& v) { return push_dispatch(c, v, container_category(c)); } // Find template typename Container::iterator find_dispatch(Container& c, const Value& value, container_tag) { return std::find(c.begin(), c.end(), value); } template typename AssociativeContainer::iterator find_dispatch(AssociativeContainer& c, const Value& value, associative_container_tag) { return c.find(value); } template typename Container::iterator find(Container& c, const Value& value) { return find_dispatch(c, value, graph_detail::container_category(c)); } // Find (const versions) template typename Container::const_iterator find_dispatch(const Container& c, const Value& value, container_tag) { return std::find(c.begin(), c.end(), value); } template typename AssociativeContainer::const_iterator find_dispatch(const AssociativeContainer& c, const Value& value, associative_container_tag) { return c.find(value); } template typename Container::const_iterator find(const Container& c, const Value& value) { return find_dispatch(c, value, graph_detail::container_category(c)); } // Equal range #if 0 // Make the dispatch fail if c is not an Associative Container (and thus // doesn't have equal_range unless it is sorted, which we cannot check // statically and is not typically true for BGL's uses of this function). template std::pair equal_range_dispatch(Container& c, const LessThanComparable& value, container_tag) { // c must be sorted for std::equal_range to behave properly. return std::equal_range(c.begin(), c.end(), value); } #endif template std::pair equal_range_dispatch(AssociativeContainer& c, const Value& value, associative_container_tag) { return c.equal_range(value); } template std::pair equal_range(Container& c, const Value& value) { return equal_range_dispatch(c, value, graph_detail::container_category(c)); } }} // namespace boost::graph_detail #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) // Stay out of the way of concept checking class templates # undef Container # undef AssociativeContainer #endif #endif // BOOST_GRAPH_DETAIL_CONTAINER_TRAITS_H