6

I'm storing a bunch of the following

struct Article {
    std::string title;
    unsigned db_id;     // id field in MediaWiki database dump
};

in a Boost.MultiIndex container, defined as

typedef boost::multi_index_container<
    Article,
    indexed_by<
        random_access<>,
        hashed_unique<tag<by_db_id>,
                      member<Article, unsigned, &Article::db_id> >,
        hashed_unique<tag<by_title>,
                      member<Article, std::string, &Article::title> >
    >
> ArticleSet;

Now I've got two iterators, one from index<by_title> and one from index<by_id>. What is the easiest way to transform these to indexes into the random access part of the container, without adding a data member to struct Article?

zxcat
  • 2,054
  • 3
  • 26
  • 40
Fred Foo
  • 355,277
  • 75
  • 744
  • 836

2 Answers2

6

Every index supports generation of an iterator by value using iterator_to. If you already have an iterator to the target value in one index, you could use this to convert to an iterator in another index.

iterator       iterator_to(const value_type& x);
const_iterator iterator_to(const value_type& x)const;

For conversion to index you can likely follow the model in random_access_index.hpp:

  iterator erase(iterator first,iterator last)
  {
    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
    BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this);
    BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this);
    BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
    BOOST_MULTI_INDEX_RND_INDEX_CHECK_INVARIANT;
    difference_type n=last-first;
    relocate(end(),first,last);
    while(n--)pop_back();
    return last;
  }
Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
  • So `iterator_to(*it)` should give me a random access iterator? And how do I convert that to an numeric index, because that's what I really need (to index into a matrix)? – Fred Foo Nov 18 '10 at 18:06
  • 2
    @larsman - judging by the internals of the random_indexed code, the requirement is that iterators on such an index are differencable, ie. `iter - index.begin()` ought to work. See edit. – Steve Townsend Nov 18 '10 at 18:11
6

iterator_to is a relatively new function in Boost (it's there since 1.35). It adds a little of the syntax sugar when using with default index. For older versions of Boost the function project is the only choise. You can use project as follows:

ArticleSet x;
// consider we've found something using `by_db_id` index
ArticleSet::index_const_iterator<by_db_id>::type it = 
  x.get<by_db_id>().find( SOME_ID );

// convert to default index ( `random_access<>` )
ArticleSet::const_iterator it1 = x.project<0>( it );
// iterator_to looks like:
ArticleSet::const_iterator it11 = x.iterator_to( *it );

// convert to index tagged with `by_title` tag
ArticleSet::index_const_iterator<by_title>::type it2 = x.project<by_title>( it );
// iterator_to doen't look better in this case:
ArticleSet::index_const_iterator<by_title>::type it2 = x.get<by_title>().iterator_to( *it );

// etc.
Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
  • Yes, that works too. I'll give you a +1 when I get new votes :) – Fred Foo Nov 18 '10 at 19:01
  • +1 I am curious @Kyrill - under the covers, both this and my answer seem to use `make_iterator` on the node value. Any reason to prefer one or the other? – Steve Townsend Nov 18 '10 at 19:05
  • A possible reason to prefer this is that it hides the dereferencing from the user. I don't really like to `<0>` bit, though... – Fred Foo Nov 18 '10 at 19:19
  • @larsman - `Boost.MultiIndex` is heavily TMP-based - think about what you get and that small ugliness seems like a small price. – Steve Townsend Nov 18 '10 at 19:29
  • @ Steve Townsend, `iterator_to` is a relatively new function in `Boost` (it's there since 1.35). It adds a little of the syntax sugar when using with default index. For older versions of `Boost` the function `project` is the only choise. – Kirill V. Lyadvinsky Nov 18 '10 at 20:07
  • @Steve Townsend, @Kirill V. Lyadvinsky, I've decided on this option eventually. You're right, Boost.MultiIndex isn't pretty anyway, but it's better than the alternative (memory-based SQLite, ugh). Portability to older Boost isn't much of an issue, btw.; I got accustomed to installing the latest version wherever I'm developing. – Fred Foo Nov 18 '10 at 22:08