# HG changeset patch
# User Peter Kovacs <kpeter@inf.elte.hu>
# Date 1248197430 -7200
# Node ID e8254acfab7d9d057a8ae90c0c73d99bc6696831
# Parent 709cfcba87778b15e1cc8a483c6754f054acd6ea
Handle multiplicity in CrossRefMap (#302)
- The inverse map is represented by std::multimap instead of std::map.
- The value iterators work with multiplicity.
- Add a function to count the items assigned to a value.
- Extend tests.
diff --git a/lemon/maps.h b/lemon/maps.h
a
|
b
|
|
1903 | 1903 | |
1904 | 1904 | /// This class provides simple invertable graph maps. |
1905 | 1905 | /// It wraps a standard graph map (\c NodeMap, \c ArcMap or \c EdgeMap) |
1906 | | /// and if a key is set to a new value then stores it in the inverse map. |
| 1906 | /// and if a key is set to a new value, then stores it in the inverse map. |
1907 | 1907 | /// |
1908 | 1908 | /// The values of the map can be accessed |
1909 | 1909 | /// with stl compatible forward iterator. |
… |
… |
|
1922 | 1922 | typedef typename ItemSetTraits<GR, K>:: |
1923 | 1923 | template Map<V>::Type Map; |
1924 | 1924 | |
1925 | | typedef std::map<V, K> Container; |
| 1925 | typedef std::multimap<V, K> Container; |
1926 | 1926 | Container _inv_map; |
1927 | 1927 | |
1928 | 1928 | public: |
… |
… |
|
1947 | 1947 | /// This iterator is an stl compatible forward |
1948 | 1948 | /// iterator on the values of the map. The values can |
1949 | 1949 | /// be accessed in the <tt>[beginValue, endValue)</tt> range. |
| 1950 | /// They are considered with multiplicity, so each value is |
| 1951 | /// traversed for each item it is assigned to. |
1950 | 1952 | class ValueIterator |
1951 | 1953 | : public std::iterator<std::forward_iterator_tag, Value> { |
1952 | 1954 | friend class CrossRefMap; |
… |
… |
|
1999 | 2001 | /// Sets the value associated with the given key. |
2000 | 2002 | void set(const Key& key, const Value& val) { |
2001 | 2003 | Value oldval = Map::operator[](key); |
2002 | | typename Container::iterator it = _inv_map.find(oldval); |
2003 | | if (it != _inv_map.end() && it->second == key) { |
2004 | | _inv_map.erase(it); |
| 2004 | typename Container::iterator it; |
| 2005 | for (it = _inv_map.equal_range(oldval).first; |
| 2006 | it != _inv_map.equal_range(oldval).second; ++it) { |
| 2007 | if (it->second == key) { |
| 2008 | _inv_map.erase(it); |
| 2009 | break; |
| 2010 | } |
2005 | 2011 | } |
2006 | 2012 | _inv_map.insert(std::make_pair(val, key)); |
2007 | 2013 | Map::set(key, val); |
… |
… |
|
2015 | 2021 | return Map::operator[](key); |
2016 | 2022 | } |
2017 | 2023 | |
2018 | | /// \brief Gives back the item by its value. |
| 2024 | /// \brief Gives back an item by its value. |
2019 | 2025 | /// |
2020 | | /// Gives back the item by its value. |
2021 | | Key operator()(const Value& key) const { |
2022 | | typename Container::const_iterator it = _inv_map.find(key); |
| 2026 | /// This function gives back an item that is assigned to |
| 2027 | /// the given value or \c INVALID if no such item exists. |
| 2028 | /// If there are more items with the same associated value, |
| 2029 | /// only one of them is returned. |
| 2030 | Key operator()(const Value& val) const { |
| 2031 | typename Container::const_iterator it = _inv_map.find(val); |
2023 | 2032 | return it != _inv_map.end() ? it->second : INVALID; |
2024 | 2033 | } |
| 2034 | |
| 2035 | /// \brief Returns the number of items with the given value. |
| 2036 | /// |
| 2037 | /// This function returns the number of items with the given value |
| 2038 | /// associated with it. |
| 2039 | int count(const Value &val) const { |
| 2040 | return _inv_map.count(val); |
| 2041 | } |
2025 | 2042 | |
2026 | 2043 | protected: |
2027 | 2044 | |
… |
… |
|
2031 | 2048 | /// \c AlterationNotifier. |
2032 | 2049 | virtual void erase(const Key& key) { |
2033 | 2050 | Value val = Map::operator[](key); |
2034 | | typename Container::iterator it = _inv_map.find(val); |
2035 | | if (it != _inv_map.end() && it->second == key) { |
2036 | | _inv_map.erase(it); |
| 2051 | typename Container::iterator it; |
| 2052 | for (it = _inv_map.equal_range(val).first; |
| 2053 | it != _inv_map.equal_range(val).second; ++it) { |
| 2054 | if (it->second == key) { |
| 2055 | _inv_map.erase(it); |
| 2056 | break; |
| 2057 | } |
2037 | 2058 | } |
2038 | 2059 | Map::erase(key); |
2039 | 2060 | } |
… |
… |
|
2045 | 2066 | virtual void erase(const std::vector<Key>& keys) { |
2046 | 2067 | for (int i = 0; i < int(keys.size()); ++i) { |
2047 | 2068 | Value val = Map::operator[](keys[i]); |
2048 | | typename Container::iterator it = _inv_map.find(val); |
2049 | | if (it != _inv_map.end() && it->second == keys[i]) { |
2050 | | _inv_map.erase(it); |
| 2069 | typename Container::iterator it; |
| 2070 | for (it = _inv_map.equal_range(val).first; |
| 2071 | it != _inv_map.equal_range(val).second; ++it) { |
| 2072 | if (it->second == keys[i]) { |
| 2073 | _inv_map.erase(it); |
| 2074 | break; |
| 2075 | } |
2051 | 2076 | } |
2052 | 2077 | } |
2053 | 2078 | Map::erase(keys); |
… |
… |
|
2083 | 2108 | |
2084 | 2109 | /// \brief Subscript operator. |
2085 | 2110 | /// |
2086 | | /// Subscript operator. It gives back the item |
2087 | | /// that was last assigned to the given value. |
| 2111 | /// Subscript operator. It gives back an item |
| 2112 | /// that is assigned to the given value or \c INVALID |
| 2113 | /// if no such item exists. |
2088 | 2114 | Value operator[](const Key& key) const { |
2089 | 2115 | return _inverted(key); |
2090 | 2116 | } |
diff --git a/test/maps_test.cc b/test/maps_test.cc
a
|
b
|
|
439 | 439 | CrossRefMap<Graph, Node, double> >(); |
440 | 440 | |
441 | 441 | Graph gr; |
442 | | CrossRefMap<Graph, Node, char> map(gr); |
| 442 | typedef CrossRefMap<Graph, Node, char> CRMap; |
| 443 | typedef CRMap::ValueIterator ValueIt; |
| 444 | CRMap map(gr); |
443 | 445 | |
444 | 446 | Node n0 = gr.addNode(); |
445 | 447 | Node n1 = gr.addNode(); |
… |
… |
|
455 | 457 | "Wrong CrossRefMap"); |
456 | 458 | check(map[n2] == 'C' && map('C') == n2 && map.inverse()['C'] == n2, |
457 | 459 | "Wrong CrossRefMap"); |
458 | | |
| 460 | check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1, |
| 461 | "Wrong CrossRefMap::count()"); |
| 462 | |
| 463 | ValueIt it = map.beginValue(); |
| 464 | check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && |
| 465 | it == map.endValue(), "Wrong value iterator"); |
| 466 | |
459 | 467 | map.set(n2, 'A'); |
460 | 468 | |
461 | 469 | check(map[n0] == 'A' && map[n1] == 'B' && map[n2] == 'A', |
… |
… |
|
464 | 472 | check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); |
465 | 473 | check(map('C') == INVALID && map.inverse()['C'] == INVALID, |
466 | 474 | "Wrong CrossRefMap"); |
| 475 | check(map.count('A') == 2 && map.count('B') == 1 && map.count('C') == 0, |
| 476 | "Wrong CrossRefMap::count()"); |
| 477 | |
| 478 | it = map.beginValue(); |
| 479 | check(*it++ == 'A' && *it++ == 'A' && *it++ == 'B' && |
| 480 | it == map.endValue(), "Wrong value iterator"); |
467 | 481 | |
468 | 482 | map.set(n0, 'C'); |
469 | 483 | |
470 | 484 | check(map[n0] == 'C' && map[n1] == 'B' && map[n2] == 'A', |
471 | 485 | "Wrong CrossRefMap"); |
472 | | check(map('A') == INVALID && map.inverse()['A'] == INVALID, |
473 | | "Wrong CrossRefMap"); |
| 486 | check(map('A') == n2 && map.inverse()['A'] == n2, "Wrong CrossRefMap"); |
474 | 487 | check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); |
475 | 488 | check(map('C') == n0 && map.inverse()['C'] == n0, "Wrong CrossRefMap"); |
| 489 | check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1, |
| 490 | "Wrong CrossRefMap::count()"); |
| 491 | |
| 492 | it = map.beginValue(); |
| 493 | check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && |
| 494 | it == map.endValue(), "Wrong value iterator"); |
476 | 495 | } |
477 | 496 | |
478 | 497 | return 0; |