You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
561 lines
18 KiB
561 lines
18 KiB
// (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 <stlfwd> header. -JGS |
|
|
|
#include <boost/next_prior.hpp> |
|
|
|
#include <algorithm> // for std::remove |
|
#include <vector> |
|
#include <list> |
|
#include <map> |
|
#include <set> |
|
#include <boost/unordered_set.hpp> |
|
#include <boost/unordered_map.hpp> |
|
|
|
#if !defined BOOST_NO_SLIST |
|
# ifdef BOOST_SLIST_HEADER |
|
# include BOOST_SLIST_HEADER |
|
# else |
|
# include <slist> |
|
# 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 <class Container> |
|
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 <class T, class Alloc> |
|
vector_tag container_category(const std::vector<T,Alloc>&) |
|
{ return vector_tag(); } |
|
|
|
template <class T, class Alloc> |
|
unstable_tag iterator_stability(const std::vector<T,Alloc>&) |
|
{ return unstable_tag(); } |
|
|
|
#if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION |
|
template <class T, class Alloc> |
|
struct container_traits< std::vector<T,Alloc> > { |
|
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 <class T, class Alloc> |
|
list_tag container_category(const std::list<T,Alloc>&) |
|
{ return list_tag(); } |
|
|
|
template <class T, class Alloc> |
|
stable_tag iterator_stability(const std::list<T,Alloc>&) |
|
{ return stable_tag(); } |
|
|
|
#if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION |
|
template <class T, class Alloc> |
|
struct container_traits< std::list<T,Alloc> > { |
|
typedef list_tag category; |
|
typedef stable_tag iterator_stability; |
|
}; |
|
#endif |
|
|
|
|
|
// std::slist |
|
#ifndef BOOST_NO_SLIST |
|
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION |
|
template <class T, class Alloc> |
|
struct container_traits<BOOST_STD_EXTENSION_NAMESPACE::slist<T,Alloc> > { |
|
typedef front_insertion_sequence_tag category; |
|
typedef stable_tag iterator_stability; |
|
}; |
|
#endif |
|
template <class T, class Alloc> |
|
front_insertion_sequence_tag container_category( |
|
const BOOST_STD_EXTENSION_NAMESPACE::slist<T,Alloc>& |
|
) |
|
{ return front_insertion_sequence_tag(); } |
|
|
|
template <class T, class Alloc> |
|
stable_tag iterator_stability( |
|
const BOOST_STD_EXTENSION_NAMESPACE::slist<T,Alloc>&) |
|
{ 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 <class Key, class Cmp, class Alloc> |
|
set_tag container_category(const std::set<Key,Cmp,Alloc>&) |
|
{ return set_tag(); } |
|
|
|
template <class Key, class Cmp, class Alloc> |
|
stable_tag iterator_stability(const std::set<Key,Cmp,Alloc>&) |
|
{ return stable_tag(); } |
|
|
|
#if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION |
|
template <class Key, class Cmp, class Alloc> |
|
struct container_traits< std::set<Key,Cmp,Alloc> > { |
|
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 <class Key, class Cmp, class Alloc> |
|
multiset_tag container_category(const std::multiset<Key,Cmp,Alloc>&) |
|
{ return multiset_tag(); } |
|
|
|
template <class Key, class Cmp, class Alloc> |
|
stable_tag iterator_stability(const std::multiset<Key,Cmp,Alloc>&) |
|
{ return stable_tag(); } |
|
|
|
#if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION |
|
template <class Key, class Cmp, class Alloc> |
|
struct container_traits< std::multiset<Key,Cmp,Alloc> > { |
|
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 <class Key, class T, class Cmp, class Alloc> |
|
struct container_traits< std::map<Key,T,Cmp,Alloc> > { |
|
typedef map_tag category; |
|
typedef stable_tag iterator_stability; |
|
}; |
|
#endif |
|
|
|
template <class Key, class T, class Cmp, class Alloc> |
|
map_tag container_category(const std::map<Key,T,Cmp,Alloc>&) |
|
{ return map_tag(); } |
|
|
|
template <class Key, class T, class Cmp, class Alloc> |
|
stable_tag iterator_stability(const std::map<Key,T,Cmp,Alloc>&) |
|
{ 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 <class Key, class T, class Cmp, class Alloc> |
|
struct container_traits< std::multimap<Key,T,Cmp,Alloc> > { |
|
typedef multimap_tag category; |
|
typedef stable_tag iterator_stability; |
|
}; |
|
#endif |
|
|
|
template <class Key, class T, class Cmp, class Alloc> |
|
multimap_tag container_category(const std::multimap<Key,T,Cmp,Alloc>&) |
|
{ return multimap_tag(); } |
|
|
|
template <class Key, class T, class Cmp, class Alloc> |
|
stable_tag iterator_stability(const std::multimap<Key,T,Cmp,Alloc>&) |
|
{ 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 <class Key, class Eq, class Hash, class Alloc> |
|
struct container_traits< boost::unordered_set<Key,Eq,Hash,Alloc> > { |
|
typedef unordered_set_tag category; |
|
typedef unstable_tag iterator_stability; |
|
}; |
|
template <class Key, class T, class Eq, class Hash, class Alloc> |
|
struct container_traits< boost::unordered_map<Key,T,Eq,Hash,Alloc> > { |
|
typedef unordered_map_tag category; |
|
typedef unstable_tag iterator_stability; |
|
}; |
|
template <class Key, class Eq, class Hash, class Alloc> |
|
struct container_traits< boost::unordered_multiset<Key,Eq,Hash,Alloc> > { |
|
typedef unordered_multiset_tag category; |
|
typedef unstable_tag iterator_stability; |
|
}; |
|
template <class Key, class T, class Eq, class Hash, class Alloc> |
|
struct container_traits< boost::unordered_multimap<Key,T,Eq,Hash,Alloc> > { |
|
typedef unordered_multimap_tag category; |
|
typedef unstable_tag iterator_stability; |
|
}; |
|
#endif |
|
template <class Key, class Eq, class Hash, class Alloc> |
|
unordered_set_tag |
|
container_category(const boost::unordered_set<Key,Eq,Hash,Alloc>&) |
|
{ return unordered_set_tag(); } |
|
|
|
template <class Key, class T, class Eq, class Hash, class Alloc> |
|
unordered_map_tag |
|
container_category(const boost::unordered_map<Key,T,Eq,Hash,Alloc>&) |
|
{ return unordered_map_tag(); } |
|
|
|
template <class Key, class Eq, class Hash, class Alloc> |
|
unstable_tag iterator_stability(const boost::unordered_set<Key,Eq,Hash,Alloc>&) |
|
{ return unstable_tag(); } |
|
|
|
template <class Key, class T, class Eq, class Hash, class Alloc> |
|
unstable_tag iterator_stability(const boost::unordered_map<Key,T,Eq,Hash,Alloc>&) |
|
{ return unstable_tag(); } |
|
template <class Key, class Eq, class Hash, class Alloc> |
|
unordered_multiset_tag |
|
container_category(const boost::unordered_multiset<Key,Eq,Hash,Alloc>&) |
|
{ return unordered_multiset_tag(); } |
|
|
|
template <class Key, class T, class Eq, class Hash, class Alloc> |
|
unordered_multimap_tag |
|
container_category(const boost::unordered_multimap<Key,T,Eq,Hash,Alloc>&) |
|
{ return unordered_multimap_tag(); } |
|
|
|
template <class Key, class Eq, class Hash, class Alloc> |
|
unstable_tag |
|
iterator_stability(const boost::unordered_multiset<Key,Eq,Hash,Alloc>&) |
|
{ return unstable_tag(); } |
|
|
|
template <class Key, class T, class Eq, class Hash, class Alloc> |
|
unstable_tag |
|
iterator_stability(const boost::unordered_multimap<Key,T,Eq,Hash,Alloc>&) |
|
{ return unstable_tag(); } |
|
#endif |
|
|
|
|
|
|
|
//=========================================================================== |
|
// Generalized Container Functions |
|
|
|
|
|
// Erase |
|
template <class Sequence, class T> |
|
void erase_dispatch(Sequence& c, const T& x, |
|
sequence_tag) |
|
{ |
|
c.erase(std::remove(c.begin(), c.end(), x), c.end()); |
|
} |
|
|
|
template <class AssociativeContainer, class T> |
|
void erase_dispatch(AssociativeContainer& c, const T& x, |
|
associative_container_tag) |
|
{ |
|
c.erase(x); |
|
} |
|
template <class Container, class T> |
|
void erase(Container& c, const T& x) |
|
{ |
|
erase_dispatch(c, x, container_category(c)); |
|
} |
|
|
|
// Erase If |
|
template <class Sequence, class Predicate, class IteratorStability> |
|
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 <class AssociativeContainer, class Predicate> |
|
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 <class AssociativeContainer, class Predicate> |
|
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 <class Container, class Predicate> |
|
void erase_if(Container& c, Predicate p) |
|
{ |
|
erase_if_dispatch(c, p, container_category(c), iterator_stability(c)); |
|
} |
|
|
|
// Push |
|
template <class Container, class T> |
|
std::pair<typename Container::iterator, bool> |
|
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 <class Container, class T> |
|
std::pair<typename Container::iterator, bool> |
|
push_dispatch(Container& c, const T& v, front_insertion_sequence_tag) |
|
{ |
|
c.push_front(v); |
|
return std::make_pair(c.begin(), true); |
|
} |
|
|
|
template <class AssociativeContainer, class T> |
|
std::pair<typename AssociativeContainer::iterator, bool> |
|
push_dispatch(AssociativeContainer& c, const T& v, |
|
unique_associative_container_tag) |
|
{ |
|
return c.insert(v); |
|
} |
|
|
|
template <class AssociativeContainer, class T> |
|
std::pair<typename AssociativeContainer::iterator, bool> |
|
push_dispatch(AssociativeContainer& c, const T& v, |
|
multiple_associative_container_tag) |
|
{ |
|
return std::make_pair(c.insert(v), true); |
|
} |
|
|
|
template <class Container, class T> |
|
std::pair<typename Container::iterator,bool> |
|
push(Container& c, const T& v) |
|
{ |
|
return push_dispatch(c, v, container_category(c)); |
|
} |
|
|
|
// Find |
|
template <class Container, class Value> |
|
typename Container::iterator |
|
find_dispatch(Container& c, |
|
const Value& value, |
|
container_tag) |
|
{ |
|
return std::find(c.begin(), c.end(), value); |
|
} |
|
|
|
template <class AssociativeContainer, class Value> |
|
typename AssociativeContainer::iterator |
|
find_dispatch(AssociativeContainer& c, |
|
const Value& value, |
|
associative_container_tag) |
|
{ |
|
return c.find(value); |
|
} |
|
|
|
template <class Container, class Value> |
|
typename Container::iterator |
|
find(Container& c, |
|
const Value& value) |
|
{ |
|
return find_dispatch(c, value, |
|
graph_detail::container_category(c)); |
|
} |
|
|
|
// Find (const versions) |
|
template <class Container, class Value> |
|
typename Container::const_iterator |
|
find_dispatch(const Container& c, |
|
const Value& value, |
|
container_tag) |
|
{ |
|
return std::find(c.begin(), c.end(), value); |
|
} |
|
|
|
template <class AssociativeContainer, class Value> |
|
typename AssociativeContainer::const_iterator |
|
find_dispatch(const AssociativeContainer& c, |
|
const Value& value, |
|
associative_container_tag) |
|
{ |
|
return c.find(value); |
|
} |
|
|
|
template <class Container, class Value> |
|
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 <class Container, |
|
class LessThanComparable> |
|
std::pair<typename Container::iterator, typename Container::iterator> |
|
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 <class AssociativeContainer, class Value> |
|
std::pair<typename AssociativeContainer::iterator, |
|
typename AssociativeContainer::iterator> |
|
equal_range_dispatch(AssociativeContainer& c, |
|
const Value& value, |
|
associative_container_tag) |
|
{ |
|
return c.equal_range(value); |
|
} |
|
|
|
template <class Container, class Value> |
|
std::pair<typename Container::iterator, typename Container::iterator> |
|
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
|
|
|