0

At the beginning I needed a map, so I used std::map.
Then, some requirements were added and I needed to also get "keys" for "value" (foos for bar), so I used

boost::bimaps::bimap<
  boost::bimaps::unordered_set_of<boost::bimaps::tagged<std::string, foo>>, 
  boost::bimaps::multiset_of<boost::bimaps::tagged<std::string, bar>>>

And after that, some more requirements were added, so now I need to store a number for every foo and from the right side view I need to be able to call <bimap>.righ.find(bar) and get pairs of (foo + number stored for foo), but I still want to be able to call <bimap>.left.find(foo) and get bar.

How to achieve that? I would prefer some modern C++ over boost if possible, but I guess it is harder to have bimap functionality without the boost.

EDIT: I should note that size matters, so I don't want to store any part involved twice and the speed also matters.

I should have something like
"foo1"+100 <-> "bar1" and "foo2"+300 <-> "bar4".
and I want to be able to call <bimap>.left.find("foo1") and get "bar1",
but also <bimap>.right.find("bar1") and get pair("foo1", 100).

Lukas Salich
  • 959
  • 2
  • 12
  • 30
  • Put the number into foo? Create a new map of foo->number? – UKMonkey Jun 04 '18 at 15:57
  • Sorry, I added a note that I don't want to store the foos twice. And I wanted to add the number into foo, but then I realized that I want to be able to search the foo without the number and get bar. – Lukas Salich Jun 04 '18 at 16:01
  • "search the foo without the number and get bar. " ok - so make a version of foo that has an optional number; which is ignored in the `operator <` (or whichever is used by boost::bimap) – UKMonkey Jun 04 '18 at 16:07
  • I think boost multiindex would be a better choice here. – n. m. could be an AI Jun 04 '18 at 16:13
  • @UKMonkey I was thinking about something like that. You mean like creating a struct with string and int and overriden operator < to use only the string part? That can work, but I expected something more neat. Thanks anyway. – Lukas Salich Jun 04 '18 at 16:15
  • @n.m. So I checked https://theboostcpplibraries.com/boost.multiindex, it seems that I somehow can use boost::multi_index::member to achieve the result. But there are 2 things: 1) it takes me some time to write it syntactically correct, 2) will it be at least same space and speed efficient as UKMonkey's solution? – Lukas Salich Jun 04 '18 at 17:12
  • On the second thought @UKMonkey's solution should work just as well. – n. m. could be an AI Jun 04 '18 at 18:23
  • K.I.S.S - Keep It Simple S..... :) when in doubt - the easiest way is the best. – UKMonkey Jun 04 '18 at 19:52
  • I agree with keep it simple, but you can use a lot of lines with very simple syntaxes or use some 1 liner that does what you want and the most neat solution is something between. I don't know, what from those 2 solutions is better, because I use boost::bimap anyway, so maybe using another boost thing can be better. I will decide tomorrow, thank you both. Maybe I just expected some third solution, but maybe there isn't any. – Lukas Salich Jun 04 '18 at 21:42
  • So I am trying to override .left.find and .left.erase instead of operator <. But I don't even know if it's possible. – Lukas Salich Jun 05 '18 at 11:43
  • It's not trivial for me, I open another question how to override the find and erase methods for left side. – Lukas Salich Jun 05 '18 at 11:57

1 Answers1

0
#include <boost/multi_index/hashed_index.hpp>
#include <boost/bimap/bimap.hpp>

using namespace std;

struct ElementType { 
  string foo; 
  string bar;
  uint64_t number; 
};

using namespace boost::multi_index;

using my_bimap = multi_index_container<
  ElementType,
  indexed_by<
    hashed_unique<member<ElementType, string, &ElementType::foo>>,
    ordered_non_unique<member<ElementType, string, &ElementType::bar>>
  >
>;

int main() {
  my_bimap instance;

  instance.insert({"foo", "bar", 0});
  instance.insert({"bar", "bar", 1});

  cout << instance.get<0>().find("bar")->foo << endl;
  cout << instance.get<0>().find("bar")->bar << endl;
  cout << instance.get<0>().find("bar")->number << endl;
  auto range = instance.get<1>().equal_range("bar");
  for (auto it = range.first; it != range.second; ++it) {
    cout << it->foo << endl;
    cout << it->number << endl;
  }

  cin.sync();
  cin.ignore();
}

Output:

bar
bar
1
foo
0
bar
1
Lukas Salich
  • 959
  • 2
  • 12
  • 30