[multiindex] hashed index, modify() and traversal
Hello, I'm modifying the elements of a multiindex container by accessing them through an hashed index (I suppose that this is faster than accessing them through the other index, which is ordered). I would like to know if I can keep going ++ on the hashed iterator as the elements of the container get changed, without modifying the same elements more than once or reaching the end() prematurely. In other words, does the re-hash change the relative positions of the elements or are they unaltered as the elements are modified? Thanks very much, Francesco
Hi Francesco, Francesco Biscani ha escrito:
Hello,
I'm modifying the elements of a multiindex container by accessing them through an hashed index (I suppose that this is faster than accessing them through the other index, which is ordered). I would like to know if I can keep going ++ on the hashed iterator as the elements of the container get changed, without modifying the same elements more than once or reaching the end() prematurely.
No, you can't.
In other words, does the re-hash change the relative positions of the elements or are they unaltered as the elements are modified?
As soon as you modify() an element, this gets repositioned accordingly: in ordered indices, to keep the ascending order; in hashed indices, where the new hash code indicates. So, you can't rely on the traversal order being preserved during a modify and traversal operation, except for sequenced and random access indices. Now, if you don't have a sequenced or random access index to base your traversal on, you still can safely modify a range of elements [first,last) as follows: 1. If you traverse an ordered index and the modifications on [first,last) are *stable* in the following sense: given it0 in [first, last) and it1=++it0, after modifying *it0 the modified element is repositioned *outside* [it1,last), then you can safely modify the range as you proposed originally. A common case of stable modifier is one that changes the associated key to a lower value, since modified elements will be repositioned before the current iterator, for instance: for(it=first;it!=last;){ // subtract 2 from current value m.modify(it++,boost::lambda::_1-=2); } 2. If you don't have an ordered index, only hashed indices, and/or your modifying operation is not stable in the sense defined above, you can prestore the original traversal order in an auxiliary external structure and use that to make sure you visit all the elements exactly once, for instance: typedef std::vector<iterator> buffer_type; buffer_type v; while(first!=last)v.push_back(first++); for(buffer_type::iterator it=v.begin();it!=v.end;){ // add 2 to current value (not stable) i.modify(*it++,boost::lambda::_1-=2); } This question was already discussed some months ago, please take a look at http://lists.boost.org/boost-users/2006/03/18048.php where some working code is also provided (look for the attached file jeff.cpp)
Thanks very much,
Francesco
HTH, please report back, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Hi Joaquín, first of all thanks for your answers. I find your replies always very helpful :) I think I've understood what you mean. Just let me recap to see if I got it right. 1. There are two ways to make sure a modification with traversal is successful: 2. I can traverse an index (hashed or ordered, it does not matter) to modify() all the elements of the container if I am sure that the modification does not change the representation of the elements with respect to the index I'm traversing on. 2a. For example, I can use the hashed index for traversing whenever I'm sure that the modifications won't change the hash value of the elements. 2b. Or I can use an ordered index whenever I'm sure that the modification does not change the position of the element in the binary search tree. 3. I can also traverse and modify an ordered index from top to bottom if I'm consistently modifying each element to place itself _higher_ in the tree than it was before. In the opposite way I can traverse bottom to top if I'm consistently modifying the element to be _lower_ in the tree. So, in my case I was using an hashed index traversal while I was changing the hash values. It's a no-go. However I also have an ordered index already defined, and the modification I want to do does not change the ordering of elements. Hence the use of a sorted index for this purpose is safe. Does this make sense? :) Thanks again, Francesco
Francesco Biscani
Hi Joaquín,
first of all thanks for your answers. I find your replies always very helpful :)
Thank you :)
I think I've understood what you mean. Just let me recap to see if I got it right.
1. There are two ways to make sure a modification with traversal is successful:
2. I can traverse an index (hashed or ordered, it does not matter) to modify() all the elements of the container if I am sure that the modification does not change the representation of the elements with respect to the index I'm traversing on. 2a. For example, I can use the hashed index for traversing whenever I'm sure that the modifications won't change the hash value of the elements. 2b. Or I can use an ordered index whenever I'm sure that the modification does not change the position of the element in the binary search tree.
Correct. In the case of ordered indices, I'd phrase this as "the modification does not change the relative order of the element", since the binary search tree it's an implementation detail after all --your statement about the binary search tree is roughly but not entirely equivalent.
3. I can also traverse and modify an ordered index from top to bottom if I'm consistently modifying each element to place itself _higher_ in the tree than it was before. In the opposite way I can traverse bottom to top if I'm consistently modifying the element to be _lower_ in the tree.
As in the 2b I'd forget about the internal binary tree; for one, you don't traverse the index from top to bottom, but from the leftmost node (which usually is not at the top) to the rightmost node. Your statement is IMHO correct if you do the following substitutions: top --> begin bottom --> end higher in the tree --> before lower in the three --> after
So, in my case I was using an hashed index traversal while I was changing the hash values. It's a no-go. However I also have an ordered index already defined, and the modification I want to do does not change the ordering of elements. Hence the use of a sorted index for this purpose is safe.
Does this make sense? :)
Absolutely. If the modifications affect only the hash part and do not change the ordering of elements, doing the traversal through the ordered index is the way to go.
Thanks again,
Francesco
Happy mofiy()ing, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
On Friday 27 October 2006 21:28, Joaquin M Lopez Munoz wrote:
Absolutely. If the modifications affect only the hash part and do not change the ordering of elements, doing the traversal through the ordered index is the way to go.
Thanks again,
Francesco
Happy mofiy()ing,
Thanks for the clarifications Joaquín, and thanks for boost::multiindex too :) Best regards, Francesco
participants (3)
-
Francesco Biscani
-
Joaquin M Lopez Munoz
-
Joaquín Mª López Muñoz