[bimap] Review of the Bimap library begins today Feb 15

Hello everyone, The review of the proposed Boost Bimap library written by Matias Capeletto starts today (February 15th, 2007) and ends after 10 days (February 25, 2007). Documentation for the library can be found online here: http://tinyurl.com/e2os3 The library can be downloaded from Boost.Vault/Containers: URL: http://www.boost-consulting.com/vault/index.php?directory=Containers Tiny URL: http://tinyurl.com/ysfclr Online documentation and the documentation package can be found here: http://tinyurl.com/y95qng --------------------------------------------------- Context: The library has been developed by Matias Capeletto with the mentoring of Joaquín M López Muñoz in the context of the Google SoC 2006. You can find more information about SoC projects here: http://code.google.com/soc/boost/about.html You can read an overview of Boost participation in Google Summer of Code 2006 written by Joaquín M López Muñoz here: http://boost.org/more/boost_soc_06_overview.html --------------------------------------------------- About the library: With Boost.Bimap you can create associative containers in which both types can be used as key. A bimap<X,Y> can be thought of as a combination of a std::map<X,Y> and a std::map<Y,X>. The learning curve of bimap is almost flat if you know how to use standard containers. A great deal of effort has been put into mapping the naming scheme of the STL in Boost.Bimap. The library is designed to match the common STL containers. Boost.Bimap offers also advanced features: -> Boost.Bimap offers much more than just a one-to-one ordered unique bidirectional map. It is possible to control the set type of each side of the relationship that the bimap represents, giving one-to-many containers, hashed bidirectional containers and others that may be more suitable to the the task at hand. -> The types of a bimap can be tagged so that each side is accessible by something closer to the problem than left and right. This leads to more readable, self-documenting code. -> The extended mapping framework allows to disable a view of a bimap, including the standard mapping containers as a particular case. Bimap has been tested in the following platforms: GCC 3.4/Linux GCC 4.0/Linux, Mac VS 7.1/Windows VS 8.0/Windows ICC 7.1/Windows ICC 8.0/Windows --------------------------------------------------- Please always state in your review, whether you think the library should be accepted as a Boost library! Additionally please consider giving feedback on the following general topics: - What is your evaluation of the design? - What is your evaluation of the implementation? - What is your evaluation of the documentation? - What is your evaluation of the potential usefulness of the library? - Did you try to use the library? With what compiler? Did you have any problems? - How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? - Are you knowledgeable about the problem domain? Ion Gaztañaga Review Manager

First, I'd like to congratulate Matias and by proxy Joaquín for their work on this library -- I think it should be accepted into boost. I've used similar constructs in several real-world projects and have used my own variant of the 'recommended bi-map' wrapper from the MI library examples. This new wrapper is better. First some detailed comments/questions: 1) Tutorial docs are wrong -- namespace should be boost::bimap not 'bimap' 2) I'd suggest that we should have a top level boost header -- boost/bimap.hpp the simply includes the bimap/bimap.hpp. Not all libs have these top level headers, but most do. It's handy to just do '#include "boost/<libname>.hpp"' 3) Why not discuss bimap in terms of value_type? Here's the example from the tutorial: typedef bimap<std::string,int> results_bimap; typedef results_bimap::relation position; results_bimap results; Now normally when dealing with std::map I'd do something like this typedef std::map<std::string, int> regular_map; typedef regular_map::value_type val_type; regular_map rm; rm.insert(val_type("foo", 1)); Turns out the same thing works for bimap -- which is good :-) typedef results_bimap::value_type bm_val_type; results_bimap rbm; rbm.insert(bm_val_type("foo", 1)); So, I would suggest that the first example should leverage this similarity instead of introduce the set<relation> stuff. 4) more tutorial -- const_iterators Since the example doesn't modify the returned objects const_iterator's might be more appropriate. Luckily, just as expected the following were available: results_bimap::right_const_iterator i = rbm.right.begin(); results_bimap::left_const_iterator i = rbm.left.begin(); 5) Please add something to the tutorial to show the behavior of trying to insert when a key is already in the map: //like std::map if one of the keys is duplicated insert fails results.insert( position("Somewhere" ,4) ); //no effect! results.insert( position("France" ,5) ); //no effect! 6) More on std::map compatibility. Ok, here's what I'm wondering. For a simple bimap if I access it like an std::map shouldn't I just see the bimap.left? That is, I'd like to be able to seamlessly use bimap in place of std::map and have the 'left view' work pretty much like a std::map where feasible. Here's where this would come up. I have a little algorithm I use to simplify map coding called 'exists'. This simplifies the usual code need to find a particular key in a collection, check against the end, and then do something. Here's what it looks like: template<class CollectionType> inline bool exists(const CollectionType& c, const typename CollectionType::key_type& key, typename CollectionType::const_iterator& outItr) { typename CollectionType::const_iterator itr = c.find(key); if (itr != c.end()) { outItr = itr; return true; } return false; } And it's used like this: regular_map rm; regular_map::const_iterator rmci; if (exists(rm, "foo", rmci)) { std::cout << rmci->second << std::endl; } else { //do something else Of course if I try this with bimap it fails because key_type doesn't exist among other things. Luckily, this works: results_bimap rbm; results_bimap::left_iterator bmci; if (exists(rbm.left, "bar", bmci)) { std::cout << "exists test left:" << bmci->second << std::endl; } So, my question is, why should the bimap give me a me the .left for the standard map methods? 7) More tutorial/example docs please!! As beautiful as the docs are, I'm like alot of programmers hate reading docs. What I want to find is an example of the code I'm trying to write so I can cut it from the docs drop it into my code and start modifying. Then if I hit a roadblock I'll go back to the docs. By the time I go back to the docs I'll already have a 'feel' for the lib. Bottom line is that there needs to be lots of examples -- there aren't enough examples in the docs. 8) I'm confused about the model when bi-map uses a 'multi-set' or 'unordered-multiset'. Do these allow duplicated keys for that side? Why no bi-multimap? Overall I'm inclined to suggest that some of these features should be removed from the library for now. The examples and tests seem to be lacking (just typedefs that don't test anything AFAICT). 9) Should it be bi-collections instead of bi-map? There's a ton of other features in the library that allow for creation of different bi-directional relations. In fact, this probably constitutes the bulk of the library. Thus, I'm wondering if the library should be renamed to account for these or they should be removed and the library stripped down to the bimap essence? ****************** Some standard question responses... What is your evaluation of the design? --> Good -- it's built on top of an already solid Boost library. What is your evaluation of the implementation? --> Didn't look long enough to comment. What is your evaluation of the documentation? --> It's very complete with reference docs -- a few missing elements: 1) compiler notes (discusses any special rules/issues for various compilers), 2) design decisions -- documents any important tradeoffs and issues, 3) change log -- after it's accepted this will record bug fixes, etc. What is your evaluation of the potential usefulness of the library? --> Quite useful. Did you try to use the library? With what compiler? Did you have any problems? --> Yes, g++-4.0 on ubuntu 64 bit Linux. How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? --> 3 hours now -- looked at preliminary versions of the library in the past. I read thru the docs and compiled some examples to test out that the library works as I would expect. Are you knowledgeable about the problem domain? --> Yes Jeff

Hi jeff, On 2/24/07, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
First, I'd like to congratulate Matias and by proxy Joaquín for their work on this library -- I think it should be accepted into boost. I've used similar constructs in several real-world projects and have used my own variant of the 'recommended bi-map' wrapper from the MI library examples. This new wrapper is better.
Thanks!
First some detailed comments/questions:
1) Tutorial docs are wrong -- namespace should be boost::bimap not 'bimap'
Yes, you are right.
2) I'd suggest that we should have a top level boost header -- boost/bimap.hpp the simply includes the bimap/bimap.hpp. Not all libs have these top level headers, but most do. It's handy to just do '#include "boost/<libname>.hpp"'
That can be done.
3) Why not discuss bimap in terms of value_type? Here's the example from the tutorial:
typedef bimap<std::string,int> results_bimap; typedef results_bimap::relation position;
results_bimap results;
Now normally when dealing with std::map I'd do something like this
typedef std::map<std::string, int> regular_map; typedef regular_map::value_type val_type;
regular_map rm; rm.insert(val_type("foo", 1));
Turns out the same thing works for bimap -- which is good :-)
typedef results_bimap::value_type bm_val_type; results_bimap rbm; rbm.insert(bm_val_type("foo", 1));
So, I would suggest that the first example should leverage this similarity instead of introduce the set<relation> stuff.
That can be confusing. But the docs will be need to be polish to help people understand the real nature of bimap. First of all. The ::relation typedef will be eliminated, it is equal to ::value_type and has only bring noise til now. I will change the first example so it only use the side views of the bimap ( .left and .right) that are the most important ones. The above view, the set of relations one must be introduced later with a whole section dedicated to it. If you want to insert elements from the left you have to use it like: typedef results_bimap::left_map_type::value_type left_val_type; // or // typedef results_bimap::left_value_type left_val_type; results_bimap rbm; rbm.left.insert(left_val_type("foo", 1)); and if you want to insert elements from the right you have to use it like: rbm.right.insert(right_value_type(1,"foo"));
4) more tutorial -- const_iterators
Since the example doesn't modify the returned objects const_iterator's might be more appropriate. Luckily, just as expected the following were available:
results_bimap::right_const_iterator i = rbm.right.begin(); results_bimap::left_const_iterator i = rbm.left.begin();
Ok, you are right.
5) Please add something to the tutorial to show the behavior of trying to insert when a key is already in the map:
//like std::map if one of the keys is duplicated insert fails results.insert( position("Somewhere" ,4) ); //no effect! results.insert( position("France" ,5) ); //no effect!
Ok, will be added.
6) More on std::map compatibility.
Ok, here's what I'm wondering. For a simple bimap if I access it like an std::map shouldn't I just see the bimap.left? That is, I'd like to be able to seamlessly use bimap in place of std::map and have the 'left view' work pretty much like a std::map where feasible. Here's where this would come up. I have a little algorithm I use to simplify map coding called 'exists'. This simplifies the usual code need to find a particular key in a collection, check against the end, and then do something. Here's what it looks like:
template<class CollectionType> inline bool exists(const CollectionType& c, const typename CollectionType::key_type& key, typename CollectionType::const_iterator& outItr) { typename CollectionType::const_iterator itr = c.find(key); if (itr != c.end()) { outItr = itr; return true; } return false; }
And it's used like this:
regular_map rm; regular_map::const_iterator rmci; if (exists(rm, "foo", rmci)) { std::cout << rmci->second << std::endl; } else { //do something else
Of course if I try this with bimap it fails because key_type doesn't exist among other things. Luckily, this works:
results_bimap rbm; results_bimap::left_iterator bmci; if (exists(rbm.left, "bar", bmci)) { std::cout << "exists test left:" << bmci->second << std::endl; }
So, my question is, why should the bimap give me a me the .left for the standard map methods?
A bimap<X,Y> bm allows you to view the bidirectional mapping as a std::map<X,Y> using bm.left and as a std::map<Y,X> using bm.right. You can work with this container using only this two views. For bm (the above view) we have some options: 1) bm can be left without any special function and so force the user to write .left or .right to refer to it. 2) bm can be the same as bm.left. This IMHO introduce an asymmetry to the interface. The left view became the more important than the right view. 3) bm can be used for something new. Give the user a new view of the mapping: a set of relations. This design is symmetric. It forces the user to write .left to refer to the std::map<X,Y> view but this is a good thing, because is documented in the code what view is being used. This option is more elegant and powerful that the other ones. Your algorithm will work with the right view too:
results_bimap rbm; results_bimap::right_iterator bmci; if (exists(rbm.right, "bar", bmci)) { std::cout << "exists test right:" << bmci->second << std::endl; }
As far as I can see the std::map compatibility is very good, for both bm.left and bm.right. The only place where this compatibility could failed is in the conversion between std::pair and the pairs used in the bimap. But if we use generic code this is not a limitation.
7) More tutorial/example docs please!!
As beautiful as the docs are, I'm like alot of programmers hate reading docs. What I want to find is an example of the code I'm trying to write so I can cut it from the docs drop it into my code and start modifying. Then if I hit a roadblock I'll go back to the docs. By the time I go back to the docs I'll already have a 'feel' for the lib. Bottom line is that there needs to be lots of examples -- there aren't enough examples in the docs.
More examples will be added.
8) I'm confused about the model when bi-map uses a 'multi-set' or 'unordered-multiset'. Do these allow duplicated keys for that side? Why no bi-multimap? Overall I'm inclined to suggest that some of these features should be removed from the library for now. The examples and tests seem to be lacking (just typedefs that don't test anything AFAICT).
These features are tested in the same way that the simpler bimap. See: test_bimap_ordered.cpp Test set_of and multiset_of test_bimap_unordered.cpp Test unordered_set_of and unordered_multiset_of test_bimap_sequenced.cpp Test list_of and vector_of
9) Should it be bi-collections instead of bi-map?
bimap is a shortcut for bidirectional mapping. The library offers a framework to create many types of containers, but all of them are about the mapping between two collection of elements...
There's a ton of other features in the library that allow for creation of different bi-directional relations. In fact, this probably constitutes the bulk of the library. Thus, I'm wondering if the library should be renamed to account for these or they should be removed and the library stripped down to the bimap essence?
IMO these features make this library more powerful with out compromising easy of use. It is necessary to have the option to change the set type of each side. Users must have a way to specify different constrains. For example between the current framework it is very simple to specify that one of the collections can have repeated elements, aka is a multiset. typedef bimap< int, multiset_of< std::string > > bm_type; The user is allow to choose if elements in each side need to be ordered, if not he can use an unordered_set for that side and gain in look up performance. typedef bimap< unordered_set_of<int>, std::string > bm_type; We have to discuss about other features, for example, the possibility of changing the set type of relations, the above view. Because the library was build on top of Boost.MultiIndex, this feature was there waiting to be implemented. I think that there are many use cases for a: typedef bimap< unordered_set_of<A>, unordered_set_of<B>, list_of_relation > bm_type; bm_type bm; ... bm_type::right_iterator r_iter = bm.right.find(b); if( r_iter != bm.right.begin() ) { ... r_iter->second == a ... } bm_type::left_iterator l_iter = bm.left.find(a); if( l_iter != bm.left.begin() ) { ... l_iter->second == b ... } for( bm_type::const_iterator i = bm.begin(), e = bm.end(); i != e ; i++ ) { std::cout << i->left << "<--->" << " i->right << std::endl; } Where you trade insertion time with the possibility of a fast search from both sides with out loosing iteration capability. What do you think about this kind of bimap? Thanks for the review Best regards Matias

Matias Capeletto wrote:
Hi jeff,
On 2/24/07, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
6) More on std::map compatibility.
...snip details...
So, my question is, why should the bimap give me a me the .left for the standard map methods?
A bimap<X,Y> bm allows you to view the bidirectional mapping as a std::map<X,Y> using bm.left and as a std::map<Y,X> using bm.right. You can work with this container using only this two views.
For bm (the above view) we have some options:
1) bm can be left without any special function and so force the user to write .left or .right to refer to it. 2) bm can be the same as bm.left. This IMHO introduce an asymmetry to the interface. The left view became the more important than the right view.
Yes, I second thought I agree with this view. I'd rather see bimap take the minimal approach now and avoid the confusion. Also, I suspect that if *I'm* really interested in providing the 'left' view as default standard I can simply derive from bimap and provide the needed types. Given this, you should probably remove some of the public typdefs because things like bimap::value_type compile and hence may be confusing. I should have to say bimap::left_value_type.
Your algorithm will work with the right view too:
results_bimap rbm; results_bimap::right_iterator bmci; if (exists(rbm.right, "bar", bmci)) { std::cout << "exists test right:" << bmci->second << std::endl; }
Yep.
As far as I can see the std::map compatibility is very good, for both bm.left and bm.right. The only place where this compatibility could failed is in the conversion between std::pair and the pairs used in the bimap. But if we use generic code this is not a limitation.
My experiments do indeed confirm at some level that .left and .right look pretty much like std::map...hardly exhaustive, but still I was happy about that.
8) I'm confused about the model when bi-map uses a 'multi-set' or 'unordered-multiset'. Do these allow duplicated keys for that side? Why no bi-multimap? Overall I'm inclined to suggest that some of these features should be removed from the library for now. The examples and tests seem to be lacking (just typedefs that don't test anything AFAICT).
These features are tested in the same way that the simpler bimap. See:
test_bimap_ordered.cpp Test set_of and multiset_of
test_bimap_unordered.cpp Test unordered_set_of and unordered_multiset_of
test_bimap_sequenced.cpp Test list_of and vector_of
Ok, I missed those. But still I'm still left wondering about these questions:
Do these allow duplicated keys for that side? Why no bi-multimap?
I didn't see a duplicated key test and perhaps I missed it, but I didn't see that explained in the docs. Also, there's no example code AFAICS for most of these advanced mappings.
9) Should it be bi-collections instead of bi-map?
bimap is a shortcut for bidirectional mapping. The library offers a framework to create many types of containers, but all of them are about the mapping between two collection of elements...
Ok, it's probably my pre-conceived notion of what bi-map is that clouded my understanding.
There's a ton of other features in the library that allow for creation of different bi-directional relations. In fact, this probably constitutes the bulk of the library. Thus, I'm wondering if the library should be renamed to account for these or they should be removed and the library stripped down to the bimap essence?
IMO these features make this library more powerful with out compromising easy of use.
It's possible for the more complex features to distract from the usability for the simple reason that there's more documentation for users to consume and understand. Sometimes as a new user when there's a problem it's hard to tell where the answer lies. Anyway, I think most of this can be solved with additional tutorial docs/examples showing the use of these more advanced features.
It is necessary to have the option to change the set type of each side. Users must have a way to specify different constrains. For example between the current framework it is very simple to specify that one of the collections can have repeated elements, aka is a multiset.
typedef bimap< int, multiset_of< std::string > > bm_type;
Ok, if I'm not mistaken this will change the interface behavior in that now: bm_type b; typedef bm_type::right_value_type vtype; b.insert(vtype(1, "foo")); b.insert(vtype(1, "foo")); will succeed. I definitely wasn't sure about this after reading the docs.
The user is allow to choose if elements in each side need to be ordered, if not he can use an unordered_set for that side and gain in look up performance.
typedef bimap< unordered_set_of<int>, std::string > bm_type;
Sure, I can certainly see the power of this. Again, the one that seems to be conspicuously absent is multimap_of which would presumably be unordered and not require a hash function. So why no multimap_of?
We have to discuss about other features, for example, the possibility of changing the set type of relations, the above view. Because the library was build on top of Boost.MultiIndex, this feature was there waiting to be implemented. I think that there are many use cases for a:
typedef bimap< unordered_set_of<A>, unordered_set_of<B>, list_of_relation > bm_type;
bm_type bm; ...
bm_type::right_iterator r_iter = bm.right.find(b); if( r_iter != bm.right.begin() ) { ... r_iter->second == a ... }
bm_type::left_iterator l_iter = bm.left.find(a); if( l_iter != bm.left.begin() ) { ... l_iter->second == b ... }
for( bm_type::const_iterator i = bm.begin(), e = bm.end(); i != e ; i++ ) { std::cout << i->left << "<--->" << " i->right << std::endl; }
Where you trade insertion time with the possibility of a fast search from both sides with out loosing iteration capability. What do you think about this kind of bimap?
Sure, I can see the utility of this feature -- I"m actually working on something now that has exactly these sort of requirements supported thru code generation. As I said, above I think at a minimum it needs a bit more attention in the tutorial docs/examples. My suggestion about 'leaving it out for now' is based on the simple point that you can always expand the library easily later (even without review), but once it's out there it's really, really hard to take back or radically change things. So if there's any doubt it would be better to keep things simpler now and add later. Jeff

On 2/25/07, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
Matias Capeletto wrote:
Hi jeff,
On 2/24/07, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
6) More on std::map compatibility.
...snip details...
So, my question is, why should the bimap give me a me the .left for the standard map methods?
A bimap<X,Y> bm allows you to view the bidirectional mapping as a std::map<X,Y> using bm.left and as a std::map<Y,X> using bm.right. You can work with this container using only this two views.
For bm (the above view) we have some options:
1) bm can be left without any special function and so force the user to write .left or .right to refer to it. 2) bm can be the same as bm.left. This IMHO introduce an asymmetry to the interface. The left view became the more important than the right view.
Yes, I second thought I agree with this view. I'd rather see bimap take the minimal approach now and avoid the confusion. Also, I suspect that if *I'm* really interested in providing the 'left' view as default standard I can simply derive from bimap and provide the needed types. Given this, you should probably remove some of the public typdefs because things like
bimap::value_type
compile and hence may be confusing. I should have to say bimap::left_value_type.
Your algorithm will work with the right view too:
results_bimap rbm; results_bimap::right_iterator bmci; if (exists(rbm.right, "bar", bmci)) { std::cout << "exists test right:" << bmci->second << std::endl; }
Yep.
As far as I can see the std::map compatibility is very good, for both bm.left and bm.right. The only place where this compatibility could failed is in the conversion between std::pair and the pairs used in the bimap. But if we use generic code this is not a limitation.
My experiments do indeed confirm at some level that .left and .right look pretty much like std::map...hardly exhaustive, but still I was happy about that.
I have not followed you here. Can you reword it?
Do these allow duplicated keys for that side? Why no bi-multimap?
I didn't see a duplicated key test and perhaps I missed it, but I didn't see that explained in the docs. Also, there's no example code AFAICS for most of these advanced mappings.
Boost.MultiIndex have extensive testing on these kind of things. Boost.Bimap tests make sure that each function calls the appropriate B.MI function. There are some in the "examples" section but it has to be extended. (They can not compilable because I make some typos that I have to correct)
9) Should it be bi-collections instead of bi-map?
bimap is a shortcut for bidirectional mapping. The library offers a framework to create many types of containers, but all of them are about the mapping between two collection of elements...
Ok, it's probably my pre-conceived notion of what bi-map is that clouded my understanding.
There's a ton of other features in the library that allow for creation of different bi-directional relations. In fact, this probably constitutes the bulk of the library. Thus, I'm wondering if the library should be renamed to account for these or they should be removed and the library stripped down to the bimap essence?
IMO these features make this library more powerful with out compromising easy of use.
It's possible for the more complex features to distract from the usability for the simple reason that there's more documentation for users to consume and understand. Sometimes as a new user when there's a problem it's hard to tell where the answer lies. Anyway, I think most of this can be solved with additional tutorial docs/examples showing the use of these more advanced features.
Ok, I am receiving tons of useful data to incorporate in the tutorial and make it better.
It is necessary to have the option to change the set type of each side. Users must have a way to specify different constrains. For example between the current framework it is very simple to specify that one of the collections can have repeated elements, aka is a multiset.
typedef bimap< int, multiset_of< std::string > > bm_type;
Ok, if I'm not mistaken this will change the interface behavior in that now:
bm_type b; typedef bm_type::right_value_type vtype; b.insert(vtype(1, "foo")); b.insert(vtype(1, "foo"));
will succeed. I definitely wasn't sure about this after reading the docs.
In order to understand how this works we have to understand the bimap as a bidirectional mapping between two collections of elements (I must add a section with a careful explanation). Each collection can have different constraints. By default the collections are set_of the elements. So they are ordered and unique. The constraints works in the same way as the standard containers. (set, multiset, unorderd_set, unordered_multiset, list and vector)
The user is allow to choose if elements in each side need to be ordered, if not he can use an unordered_set for that side and gain in look up performance.
typedef bimap< unordered_set_of<int>, std::string > bm_type;
Sure, I can certainly see the power of this. Again, the one that seems to be conspicuously absent is multimap_of which would presumably be unordered and not require a hash function. So why no multimap_of?
We are controlling each collections constraints. Can you tell me what kind of bimap you are looking for?
We have to discuss about other features, for example, the possibility of changing the set type of relations, the above view. Because the library was build on top of Boost.MultiIndex, this feature was there waiting to be implemented. I think that there are many use cases for a:
typedef bimap< unordered_set_of<A>, unordered_set_of<B>, list_of_relation > bm_type;
bm_type bm; ...
bm_type::right_iterator r_iter = bm.right.find(b); if( r_iter != bm.right.begin() ) { ... r_iter->second == a ... }
bm_type::left_iterator l_iter = bm.left.find(a); if( l_iter != bm.left.begin() ) { ... l_iter->second == b ... }
for( bm_type::const_iterator i = bm.begin(), e = bm.end(); i != e ; i++ ) { std::cout << i->left << "<--->" << " i->right << std::endl; }
Where you trade insertion time with the possibility of a fast search from both sides with out loosing iteration capability. What do you think about this kind of bimap?
Sure, I can see the utility of this feature -- I"m actually working on something now that has exactly these sort of requirements supported thru code generation. As I said, above I think at a minimum it needs a bit more attention in the tutorial docs/examples. My suggestion about 'leaving it out for now' is based on the simple point that you can always expand the library easily later (even without review), but once it's out there it's really, really hard to take back or radically change things. So if there's any doubt it would be better to keep things simpler now and add later.
Ok. It may be better to start with a smaller interface. Lets see how things evolve in the next days. Regards Matias

Matias Capeletto wrote:
My experiments do indeed confirm at some level that .left and .right look pretty much like std::map...hardly exhaustive, but still I was happy about that.
I have not followed you here. Can you reword it?
I was just saying that when I use bm.left of bm.right I got behavior that looked like an std::map. I only did a few tests, so it isn't 'proof' of compatibility, but I did find any problems. Bottom line is it work as I expected and well :-)
Do these allow duplicated keys for that side? Why no bi-multimap?
I didn't see a duplicated key test and perhaps I missed it, but I didn't see that explained in the docs. Also, there's no example code AFAICS for most of these advanced mappings.
Boost.MultiIndex have extensive testing on these kind of things. Boost.Bimap tests make sure that each function calls the appropriate B.MI function.
I see. Well, that makes me a bit uncomfortable in case there is a change to MI that breaks your behavior silently. So I'd like to see a few tests at least.
There are some in the "examples" section but it has to be extended. (They can not compilable because I make some typos that I have to correct)
Ok, I'll assume that's on your todo list.
It is necessary to have the option to change the set type of each side. Users must have a way to specify different constrains. For example between the current framework it is very simple to specify that one of the collections can have repeated elements, aka is a multiset.
typedef bimap< int, multiset_of< std::string > > bm_type; Ok, if I'm not mistaken this will change the interface behavior in that now:
bm_type b; typedef bm_type::right_value_type vtype; b.insert(vtype(1, "foo")); b.insert(vtype(1, "foo"));
will succeed. I definitely wasn't sure about this after reading the docs.
In order to understand how this works we have to understand the bimap as a bidirectional mapping between two collections of elements (I must add a section with a careful explanation). Each collection can have different constraints. By default the collections are set_of the elements. So they are ordered and unique. The constraints works in the same way as the standard containers. (set, multiset, unorderd_set, unordered_multiset, list and vector)
Well, at the end of the day, this is a request for doc clarification. Again mostly to do with a lack of tutorial/examples showing the advanced features here. The docs were clear enough that I was able to guess, but I'd have to write a program to be 100% sure. I shouldn't have to do that.
The user is allow to choose if elements in each side need to be ordered, if not he can use an unordered_set for that side and gain in look up performance.
typedef bimap< unordered_set_of<int>, std::string > bm_type; Sure, I can certainly see the power of this. Again, the one that seems to be conspicuously absent is multimap_of which would presumably be unordered and not require a hash function. So why no multimap_of?
We are controlling each collections constraints. Can you tell me what kind of bimap you are looking for?
Well after some additional thinking I guess it's 'almost the same'. That is, I think the type requirements for set and map are the same. Only thing is set provides and ordering which map does not. So actually, this is one small departure from what I was expecting. Anyway, I guess multimap_of is not required because it's really covered by multiset_of.
Sure, I can see the utility of this feature -- I"m actually working on something now that has exactly these sort of requirements supported thru code generation. As I said, above I think at a minimum it needs a bit more attention in the tutorial docs/examples. My suggestion about 'leaving it out for now' is based on the simple point that you can always expand the library easily later (even without review), but once it's out there it's really, really hard to take back or radically change things. So if there's any doubt it would be better to keep things simpler now and add later.
Ok. It may be better to start with a smaller interface. Lets see how things evolve in the next days.
I'm ok either way -- up to you -- after all, you get to maintain it ;-) Jeff
participants (3)
-
Ion Gaztañaga
-
Jeff Garland
-
Matias Capeletto