container_traits.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. // (C) Copyright Jeremy Siek 2004
  2. // (C) Copyright Thomas Claveirole 2010
  3. // (C) Copyright Ignacy Gawedzki 2010
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_GRAPH_DETAIL_CONTAINER_TRAITS_H
  8. #define BOOST_GRAPH_DETAIL_CONTAINER_TRAITS_H
  9. // Sure would be nice to be able to forward declare these
  10. // instead of pulling in all the headers. Too bad that
  11. // is not legal. There ought to be a standard <stlfwd> header. -JGS
  12. #include <boost/next_prior.hpp>
  13. #include <algorithm> // for std::remove
  14. #include <vector>
  15. #include <list>
  16. #include <map>
  17. #include <set>
  18. #include <boost/unordered_set.hpp>
  19. #include <boost/unordered_map.hpp>
  20. #if !defined BOOST_NO_SLIST
  21. # ifdef BOOST_SLIST_HEADER
  22. # include BOOST_SLIST_HEADER
  23. # else
  24. # include <slist>
  25. # endif
  26. #endif
  27. #if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
  28. // Stay out of the way of concept checking class templates
  29. # define Container Container_
  30. # define AssociativeContainer AssociativeContainer_
  31. #endif
  32. // The content of this file is in 'graph_detail' because otherwise
  33. // there will be name clashes with
  34. // sandbox/boost/sequence_algo/container_traits.hpp
  35. // The 'detail' subnamespace will still cause problems.
  36. namespace boost { namespace graph_detail {
  37. //======================================================================
  38. // Container Category Tags
  39. //
  40. // They use virtual inheritance because there are lots of
  41. // inheritance diamonds.
  42. struct container_tag { };
  43. struct forward_container_tag : virtual public container_tag { };
  44. struct reversible_container_tag : virtual public forward_container_tag { };
  45. struct random_access_container_tag
  46. : virtual public reversible_container_tag { };
  47. struct sequence_tag : virtual public forward_container_tag { };
  48. struct associative_container_tag : virtual public forward_container_tag { };
  49. struct sorted_associative_container_tag
  50. : virtual public associative_container_tag,
  51. virtual public reversible_container_tag { };
  52. struct front_insertion_sequence_tag : virtual public sequence_tag { };
  53. struct back_insertion_sequence_tag : virtual public sequence_tag { };
  54. struct unique_associative_container_tag
  55. : virtual public associative_container_tag { };
  56. struct multiple_associative_container_tag
  57. : virtual public associative_container_tag { };
  58. struct simple_associative_container_tag
  59. : virtual public associative_container_tag { };
  60. struct pair_associative_container_tag
  61. : virtual public associative_container_tag { };
  62. //======================================================================
  63. // Iterator Stability Tags
  64. //
  65. // Do mutating operations such as insert/erase/resize invalidate all
  66. // outstanding iterators?
  67. struct stable_tag { };
  68. struct unstable_tag { };
  69. //======================================================================
  70. // Container Traits Class and container_category() function
  71. #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  72. // don't use this unless there is partial specialization
  73. template <class Container>
  74. struct container_traits {
  75. typedef typename Container::category category;
  76. typedef typename Container::iterator_stability iterator_stability;
  77. };
  78. #endif
  79. // Use this as a compile-time assertion that X is stable
  80. inline void require_stable(stable_tag) { }
  81. // std::vector
  82. struct vector_tag :
  83. virtual public random_access_container_tag,
  84. virtual public back_insertion_sequence_tag { };
  85. template <class T, class Alloc>
  86. vector_tag container_category(const std::vector<T,Alloc>&)
  87. { return vector_tag(); }
  88. template <class T, class Alloc>
  89. unstable_tag iterator_stability(const std::vector<T,Alloc>&)
  90. { return unstable_tag(); }
  91. #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  92. template <class T, class Alloc>
  93. struct container_traits< std::vector<T,Alloc> > {
  94. typedef vector_tag category;
  95. typedef unstable_tag iterator_stability;
  96. };
  97. #endif
  98. // std::list
  99. struct list_tag :
  100. virtual public reversible_container_tag,
  101. virtual public back_insertion_sequence_tag
  102. // this causes problems for push_dispatch...
  103. // virtual public front_insertion_sequence_tag
  104. { };
  105. template <class T, class Alloc>
  106. list_tag container_category(const std::list<T,Alloc>&)
  107. { return list_tag(); }
  108. template <class T, class Alloc>
  109. stable_tag iterator_stability(const std::list<T,Alloc>&)
  110. { return stable_tag(); }
  111. #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  112. template <class T, class Alloc>
  113. struct container_traits< std::list<T,Alloc> > {
  114. typedef list_tag category;
  115. typedef stable_tag iterator_stability;
  116. };
  117. #endif
  118. // std::slist
  119. #ifndef BOOST_NO_SLIST
  120. # ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  121. template <class T, class Alloc>
  122. struct container_traits<BOOST_STD_EXTENSION_NAMESPACE::slist<T,Alloc> > {
  123. typedef front_insertion_sequence_tag category;
  124. typedef stable_tag iterator_stability;
  125. };
  126. #endif
  127. template <class T, class Alloc>
  128. front_insertion_sequence_tag container_category(
  129. const BOOST_STD_EXTENSION_NAMESPACE::slist<T,Alloc>&
  130. )
  131. { return front_insertion_sequence_tag(); }
  132. template <class T, class Alloc>
  133. stable_tag iterator_stability(
  134. const BOOST_STD_EXTENSION_NAMESPACE::slist<T,Alloc>&)
  135. { return stable_tag(); }
  136. #endif
  137. // std::set
  138. struct set_tag :
  139. virtual public sorted_associative_container_tag,
  140. virtual public simple_associative_container_tag,
  141. virtual public unique_associative_container_tag
  142. { };
  143. template <class Key, class Cmp, class Alloc>
  144. set_tag container_category(const std::set<Key,Cmp,Alloc>&)
  145. { return set_tag(); }
  146. template <class Key, class Cmp, class Alloc>
  147. stable_tag iterator_stability(const std::set<Key,Cmp,Alloc>&)
  148. { return stable_tag(); }
  149. #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  150. template <class Key, class Cmp, class Alloc>
  151. struct container_traits< std::set<Key,Cmp,Alloc> > {
  152. typedef set_tag category;
  153. typedef stable_tag iterator_stability;
  154. };
  155. #endif
  156. // std::multiset
  157. struct multiset_tag :
  158. virtual public sorted_associative_container_tag,
  159. virtual public simple_associative_container_tag,
  160. virtual public multiple_associative_container_tag
  161. { };
  162. template <class Key, class Cmp, class Alloc>
  163. multiset_tag container_category(const std::multiset<Key,Cmp,Alloc>&)
  164. { return multiset_tag(); }
  165. template <class Key, class Cmp, class Alloc>
  166. stable_tag iterator_stability(const std::multiset<Key,Cmp,Alloc>&)
  167. { return stable_tag(); }
  168. #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  169. template <class Key, class Cmp, class Alloc>
  170. struct container_traits< std::multiset<Key,Cmp,Alloc> > {
  171. typedef multiset_tag category;
  172. typedef stable_tag iterator_stability;
  173. };
  174. #endif
  175. // deque
  176. // std::map
  177. struct map_tag :
  178. virtual public sorted_associative_container_tag,
  179. virtual public pair_associative_container_tag,
  180. virtual public unique_associative_container_tag
  181. { };
  182. #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  183. template <class Key, class T, class Cmp, class Alloc>
  184. struct container_traits< std::map<Key,T,Cmp,Alloc> > {
  185. typedef map_tag category;
  186. typedef stable_tag iterator_stability;
  187. };
  188. #endif
  189. template <class Key, class T, class Cmp, class Alloc>
  190. map_tag container_category(const std::map<Key,T,Cmp,Alloc>&)
  191. { return map_tag(); }
  192. template <class Key, class T, class Cmp, class Alloc>
  193. stable_tag iterator_stability(const std::map<Key,T,Cmp,Alloc>&)
  194. { return stable_tag(); }
  195. // std::multimap
  196. struct multimap_tag :
  197. virtual public sorted_associative_container_tag,
  198. virtual public pair_associative_container_tag,
  199. virtual public multiple_associative_container_tag
  200. { };
  201. #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  202. template <class Key, class T, class Cmp, class Alloc>
  203. struct container_traits< std::multimap<Key,T,Cmp,Alloc> > {
  204. typedef multimap_tag category;
  205. typedef stable_tag iterator_stability;
  206. };
  207. #endif
  208. template <class Key, class T, class Cmp, class Alloc>
  209. multimap_tag container_category(const std::multimap<Key,T,Cmp,Alloc>&)
  210. { return multimap_tag(); }
  211. template <class Key, class T, class Cmp, class Alloc>
  212. stable_tag iterator_stability(const std::multimap<Key,T,Cmp,Alloc>&)
  213. { return stable_tag(); }
  214. // hash_set, hash_map
  215. struct unordered_set_tag :
  216. virtual public simple_associative_container_tag,
  217. virtual public unique_associative_container_tag
  218. { };
  219. struct unordered_multiset_tag :
  220. virtual public simple_associative_container_tag,
  221. virtual public multiple_associative_container_tag
  222. { };
  223. struct unordered_map_tag :
  224. virtual public pair_associative_container_tag,
  225. virtual public unique_associative_container_tag
  226. { };
  227. struct unordered_multimap_tag :
  228. virtual public pair_associative_container_tag,
  229. virtual public multiple_associative_container_tag
  230. { };
  231. #ifndef BOOST_NO_HASH
  232. #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  233. template <class Key, class Eq, class Hash, class Alloc>
  234. struct container_traits< boost::unordered_set<Key,Eq,Hash,Alloc> > {
  235. typedef unordered_set_tag category;
  236. typedef unstable_tag iterator_stability;
  237. };
  238. template <class Key, class T, class Eq, class Hash, class Alloc>
  239. struct container_traits< boost::unordered_map<Key,T,Eq,Hash,Alloc> > {
  240. typedef unordered_map_tag category;
  241. typedef unstable_tag iterator_stability;
  242. };
  243. template <class Key, class Eq, class Hash, class Alloc>
  244. struct container_traits< boost::unordered_multiset<Key,Eq,Hash,Alloc> > {
  245. typedef unordered_multiset_tag category;
  246. typedef unstable_tag iterator_stability;
  247. };
  248. template <class Key, class T, class Eq, class Hash, class Alloc>
  249. struct container_traits< boost::unordered_multimap<Key,T,Eq,Hash,Alloc> > {
  250. typedef unordered_multimap_tag category;
  251. typedef unstable_tag iterator_stability;
  252. };
  253. #endif
  254. template <class Key, class Eq, class Hash, class Alloc>
  255. unordered_set_tag
  256. container_category(const boost::unordered_set<Key,Eq,Hash,Alloc>&)
  257. { return unordered_set_tag(); }
  258. template <class Key, class T, class Eq, class Hash, class Alloc>
  259. unordered_map_tag
  260. container_category(const boost::unordered_map<Key,T,Eq,Hash,Alloc>&)
  261. { return unordered_map_tag(); }
  262. template <class Key, class Eq, class Hash, class Alloc>
  263. unstable_tag iterator_stability(const boost::unordered_set<Key,Eq,Hash,Alloc>&)
  264. { return unstable_tag(); }
  265. template <class Key, class T, class Eq, class Hash, class Alloc>
  266. unstable_tag iterator_stability(const boost::unordered_map<Key,T,Eq,Hash,Alloc>&)
  267. { return unstable_tag(); }
  268. template <class Key, class Eq, class Hash, class Alloc>
  269. unordered_multiset_tag
  270. container_category(const boost::unordered_multiset<Key,Eq,Hash,Alloc>&)
  271. { return unordered_multiset_tag(); }
  272. template <class Key, class T, class Eq, class Hash, class Alloc>
  273. unordered_multimap_tag
  274. container_category(const boost::unordered_multimap<Key,T,Eq,Hash,Alloc>&)
  275. { return unordered_multimap_tag(); }
  276. template <class Key, class Eq, class Hash, class Alloc>
  277. unstable_tag
  278. iterator_stability(const boost::unordered_multiset<Key,Eq,Hash,Alloc>&)
  279. { return unstable_tag(); }
  280. template <class Key, class T, class Eq, class Hash, class Alloc>
  281. unstable_tag
  282. iterator_stability(const boost::unordered_multimap<Key,T,Eq,Hash,Alloc>&)
  283. { return unstable_tag(); }
  284. #endif
  285. //===========================================================================
  286. // Generalized Container Functions
  287. // Erase
  288. template <class Sequence, class T>
  289. void erase_dispatch(Sequence& c, const T& x,
  290. sequence_tag)
  291. {
  292. c.erase(std::remove(c.begin(), c.end(), x), c.end());
  293. }
  294. template <class AssociativeContainer, class T>
  295. void erase_dispatch(AssociativeContainer& c, const T& x,
  296. associative_container_tag)
  297. {
  298. c.erase(x);
  299. }
  300. template <class Container, class T>
  301. void erase(Container& c, const T& x)
  302. {
  303. erase_dispatch(c, x, container_category(c));
  304. }
  305. // Erase If
  306. template <class Sequence, class Predicate, class IteratorStability>
  307. void erase_if_dispatch(Sequence& c, Predicate p,
  308. sequence_tag, IteratorStability)
  309. {
  310. #if 0
  311. c.erase(std::remove_if(c.begin(), c.end(), p), c.end());
  312. #else
  313. if (! c.empty())
  314. c.erase(std::remove_if(c.begin(), c.end(), p), c.end());
  315. #endif
  316. }
  317. template <class AssociativeContainer, class Predicate>
  318. void erase_if_dispatch(AssociativeContainer& c, Predicate p,
  319. associative_container_tag, stable_tag)
  320. {
  321. typename AssociativeContainer::iterator i, next;
  322. for (i = next = c.begin(); next != c.end(); i = next) {
  323. ++next;
  324. if (p(*i))
  325. c.erase(i);
  326. }
  327. }
  328. template <class AssociativeContainer, class Predicate>
  329. void erase_if_dispatch(AssociativeContainer& c, Predicate p,
  330. associative_container_tag, unstable_tag)
  331. {
  332. // This method is really slow, so hopefully we won't have any
  333. // associative containers with unstable iterators!
  334. // Is there a better way to do this?
  335. typename AssociativeContainer::iterator i;
  336. typename AssociativeContainer::size_type n = c.size();
  337. while (n--)
  338. for (i = c.begin(); i != c.end(); ++i)
  339. if (p(*i)) {
  340. c.erase(i);
  341. break;
  342. }
  343. }
  344. template <class Container, class Predicate>
  345. void erase_if(Container& c, Predicate p)
  346. {
  347. erase_if_dispatch(c, p, container_category(c), iterator_stability(c));
  348. }
  349. // Push
  350. template <class Container, class T>
  351. std::pair<typename Container::iterator, bool>
  352. push_dispatch(Container& c, const T& v, back_insertion_sequence_tag)
  353. {
  354. c.push_back(v);
  355. return std::make_pair(boost::prior(c.end()), true);
  356. }
  357. template <class Container, class T>
  358. std::pair<typename Container::iterator, bool>
  359. push_dispatch(Container& c, const T& v, front_insertion_sequence_tag)
  360. {
  361. c.push_front(v);
  362. return std::make_pair(c.begin(), true);
  363. }
  364. template <class AssociativeContainer, class T>
  365. std::pair<typename AssociativeContainer::iterator, bool>
  366. push_dispatch(AssociativeContainer& c, const T& v,
  367. unique_associative_container_tag)
  368. {
  369. return c.insert(v);
  370. }
  371. template <class AssociativeContainer, class T>
  372. std::pair<typename AssociativeContainer::iterator, bool>
  373. push_dispatch(AssociativeContainer& c, const T& v,
  374. multiple_associative_container_tag)
  375. {
  376. return std::make_pair(c.insert(v), true);
  377. }
  378. template <class Container, class T>
  379. std::pair<typename Container::iterator,bool>
  380. push(Container& c, const T& v)
  381. {
  382. return push_dispatch(c, v, container_category(c));
  383. }
  384. // Find
  385. template <class Container, class Value>
  386. typename Container::iterator
  387. find_dispatch(Container& c,
  388. const Value& value,
  389. container_tag)
  390. {
  391. return std::find(c.begin(), c.end(), value);
  392. }
  393. template <class AssociativeContainer, class Value>
  394. typename AssociativeContainer::iterator
  395. find_dispatch(AssociativeContainer& c,
  396. const Value& value,
  397. associative_container_tag)
  398. {
  399. return c.find(value);
  400. }
  401. template <class Container, class Value>
  402. typename Container::iterator
  403. find(Container& c,
  404. const Value& value)
  405. {
  406. return find_dispatch(c, value,
  407. graph_detail::container_category(c));
  408. }
  409. // Find (const versions)
  410. template <class Container, class Value>
  411. typename Container::const_iterator
  412. find_dispatch(const Container& c,
  413. const Value& value,
  414. container_tag)
  415. {
  416. return std::find(c.begin(), c.end(), value);
  417. }
  418. template <class AssociativeContainer, class Value>
  419. typename AssociativeContainer::const_iterator
  420. find_dispatch(const AssociativeContainer& c,
  421. const Value& value,
  422. associative_container_tag)
  423. {
  424. return c.find(value);
  425. }
  426. template <class Container, class Value>
  427. typename Container::const_iterator
  428. find(const Container& c,
  429. const Value& value)
  430. {
  431. return find_dispatch(c, value,
  432. graph_detail::container_category(c));
  433. }
  434. // Equal range
  435. #if 0
  436. // Make the dispatch fail if c is not an Associative Container (and thus
  437. // doesn't have equal_range unless it is sorted, which we cannot check
  438. // statically and is not typically true for BGL's uses of this function).
  439. template <class Container,
  440. class LessThanComparable>
  441. std::pair<typename Container::iterator, typename Container::iterator>
  442. equal_range_dispatch(Container& c,
  443. const LessThanComparable& value,
  444. container_tag)
  445. {
  446. // c must be sorted for std::equal_range to behave properly.
  447. return std::equal_range(c.begin(), c.end(), value);
  448. }
  449. #endif
  450. template <class AssociativeContainer, class Value>
  451. std::pair<typename AssociativeContainer::iterator,
  452. typename AssociativeContainer::iterator>
  453. equal_range_dispatch(AssociativeContainer& c,
  454. const Value& value,
  455. associative_container_tag)
  456. {
  457. return c.equal_range(value);
  458. }
  459. template <class Container, class Value>
  460. std::pair<typename Container::iterator, typename Container::iterator>
  461. equal_range(Container& c,
  462. const Value& value)
  463. {
  464. return equal_range_dispatch(c, value,
  465. graph_detail::container_category(c));
  466. }
  467. }} // namespace boost::graph_detail
  468. #if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
  469. // Stay out of the way of concept checking class templates
  470. # undef Container
  471. # undef AssociativeContainer
  472. #endif
  473. #endif // BOOST_GRAPH_DETAIL_CONTAINER_TRAITS_H