container_traits.hpp 19 KB

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