Boost logo

Boost Users :

From: JOAQUIN LOPEZ MU?Z (joaquin_at_[hidden])
Date: 2006-03-14 17:09:59


Jeff Flinn wrote:
> It would be nice to have a modify_range/modify_key_range that would
apply a
> function object to each deref'd iterator in the range. Since the
multi_index
> iterator derefences to a const value_type&, one can not use
std::for_each in
> particular to apply modifications. Or am I missing something.

Hello Jeff,

I think it is possible to have what you want
without requiring that a new facility be provided
by Boost.MultiIndex itself. For you can write:

  template<typename Index,typename Modifier>
  void modify_range(
    Index& i,typename Index::iterator first,typename Index::iterator
last,
    Modifier mod)
  {
    while(first!=last)i.modify(first++,mod);
  }

and use it as in the following example:

  struct adder
  {
    adder(int n):n(n){}
    void operator()(int& x)const{x+=n;}
    
  private:
    int n;
  };

  typedef multi_index_container<
    int,
    indexed_by<
      ordered_non_unique<boost::multi_index::identity<int> >
>
> multi_index_type;
   
  multi_index_type m;
  for(int i=0;i<10;++i)m.insert(i);
  
  modify_range(m,m.begin(),m.end(),adder(-2));

or with Boost.Lambda if you prefer:

  modify_range(m,m.begin(),m.end(),_1-=2);

There is a problem, though: consider the following:

// buggy call ro modify_range
modify_range(m,m.begin(),m.end(),adder(2));

What's the problem with this? Well, after *increasing*
the value of an element, this is repositioned
further to the end of the container, and consequentely
modify_range will visit it again and engage in a
neverending loop (modulo overflows.) For this situations
you can use a special (albeit slower) variation that
records the range before starting modifying the
elements:

  template<typename Index,typename Modifier>
  void modify_unstable_range(
    Index& i,typename Index::iterator first,typename Index::iterator
last,
    Modifier mod)
  {
    typedef std::vector<typename Index::iterator> buffer_type;
    buffer_type v;
    while(first!=last)v.push_back(first++);
  
    for(typename buffer_type::iterator it=v.begin(),it_end=v.end();
        it!=it_end;i.modify(*it++,mod));
  }

  // calling modify_unstable_range is now OK
  modify_unstable_range(m,m.begin(),m.end(),adder(2));

I hope my explanations are clear enough. Does this satisfy
your needs? You can find attached a complete example
exercising these little utilities. modify_key_range would
be a simple variation on this stuff.

HTH,

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo




Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net