[/license Boost.Bimap Copyright (c) 2006-2007 Matias Capeletto 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) ] [/ QuickBook Document version 1.4 ] [section One minute tutorial] [heading What is a bimap?] A Bimap is a data structure that represents bidirectional relations between elements of two collections. The container is designed to work as two opposed STL maps. A bimap between a collection `X` and a collection `Y` can be viewed as a map from `X` to `Y` (this view will be called the ['left map view]) or as a map from `Y` to `X` (known as the ['right map view]). Additionally, the bimap can also be viewed as a set of relations between `X` and `Y` (named the ['collection of relations view]). The following code creates an empty bimap container: typedef bimap bm_type; bm_type bm; Given this code, the following is the complete description of the resulting bimap. [footnote A type is ['signature-compatible] with other type if it has the same signature for functions and metadata. Preconditions, postconditions and the order of operations need not be the same. ] * `bm.left` is signature-compatible with `std::map` * `bm.right` is signature-compatible with `std::map` * `bm` is signature-compatible with `std::set< relation >` __SIMPLE_BIMAP__ You can see how a bimap container offers three views over the same collection of bidirectional relations. If we have any generic function that work with maps template< class MapType > void print_map(const MapType & m) { typedef typename MapType::const_iterator const_iterator; for( const_iterator iter = m.begin(), iend = m.end(); iter != iend; ++iter ) { std::cout << iter->first << "-->" << iter->second << std::endl; } } We can use the ['left map view] and the ['right map view] with it bimap< int, std::string > bm; ... print_map( bm.left ); print_map( bm.right ); And the output will be [pre [^1 --> one] [^2 --> two] ... [^one --> 1] [^two --> 2] ... ] [heading Layout of the relation and the pairs of a bimap] The `relation` class represents two related elements. The two values are named left and right to express the symmetry of this type. The bimap pair classes are signature-compatible with `std::pairs`. __RELATION_AND_PAIR__ [heading Step by step] [import ../example/step_by_step.cpp] A convenience header is available in the boost directory: #include Lets define a bidirectional map between integers and strings: [code_step_by_step_definition] [heading The collection of relations view] Remember that `bm` alone can be used as a set of relations. We can insert elements or iterate over them using this view. [code_step_by_step_set_of_relations_view] [heading The left map view] `bm.left` works like a `std::map< int, std::string >`. We use it in the same way we will use a standard map. [code_step_by_step_left_map_view] [heading The right map view] `bm.right` works like a `std::map< std::string, int >`. It is important to note that the key is the first type and the data is the second one, exactly as with standard maps. [code_step_by_step_right_map_view] [heading Differences with std::map] The main difference between bimap views and their standard containers counterparts is that, because of the bidirectional nature of a bimap, the values stored in it can not be modified directly using iterators. For example, when a `std::map` iterator is dereferenced the return type is `std::pair`, so the following code is valid: `m.begin()->second = new_value;`. However dereferencing a `bimap::left_iterator` returns a type that is ['signature-compatible] with a `std::pair` bm.left.find(1)->second = "1"; // Compilation error If you insert `(1,"one")` and `(1,"1")` in a `std::map` the second insertion will have no effect. In a `bimap` both keys have to remain unique. The insertion may fail in other situations too. Lets see an example bm.clear(); bm.insert( bm_type::value_type( 1, "one" ) ); bm.insert( bm_type::value_type( 1, "1" ) ); // No effect! bm.insert( bm_type::value_type( 2, "one" ) ); // No effect! assert( bm.size() == 1 ); [heading A simple example] Look how you can reuse code that is intend to be used with std::maps, like the print_map function in this example. [@../../example/simple_bimap.cpp Go to source code] [code_simple_bimap] The output of this program will be the following: [pre [^The number of countries is 4] [^The winner is Argentina] [^Countries names ordered by their final position:] [^1) Argentina] [^2) Spain] [^3) Germany] [^4) France] [^Countries names ordered alphabetically along with their final position:] [^Argentina ends in position 1] [^France ends in position 4] [^Germany ends in position 3] [^Spain ends in position 2] ] [heading Continuing the journey] For information on function signatures, see any standard library documentation or read the [link boost_bimap.reference reference] section of this documentation. [caution Be aware that a bidirectional map is only signature-compatible with standard containers. Some functions may give different results, such as in the case of inserting a pair into the left map where the second value conflicts with a stored relation in the container. The functions may be slower in a bimap because of the duplicated constraints. It is strongly recommended that you read [link boost_bimap.the_tutorial The full tutorial] if you intend to use a bimap in a serious project. ] [endsect]