[containers] defining the insertion point of non-unique keys

Hi @boost,
I'm looking for the solution to the following problem:
there is a collection of objects and I want to find a particular object
by two different keys. The first key is unique, so there is no problem.
The second key however is non-unique and if I search for an object using
this key I want to find the element that was inserted last in that
sequence. Neither boost::multindex nor boost:intrusive seems to have
solutions right at hand. If using boost::multindex I could try to insert
a new element in the non-unique sequence using the lower_bound
iterator of that sequence as a hint. However it is not documented that
in that case the element is always inserted before the hint. Same is
true for
boost:intrusive::multi_set/multi_map. And I'm not able to swap the
position of two adjacent elements in a multi_set or multi_map, if they
have equal keys.
To illustrate the problem, here is some code:
struct A
{
int a; // non-unique key
void* b; // unique key
// stuff
};
using namespace boost::multi_index;
typedef multi_index_container >,
ordered_unique

Olaf Krzikalla escribió:
Hi @boost,
I'm looking for the solution to the following problem: there is a collection of objects and I want to find a particular object by two different keys. The first key is unique, so there is no problem. The second key however is non-unique and if I search for an object using this key I want to find the element that was inserted last in that sequence. Neither boost::multindex nor boost:intrusive seems to have solutions right at hand. If using boost::multindex I could try to insert a new element in the non-unique sequence using the lower_bound iterator of that sequence as a hint. However it is not documented that in that case the element is always inserted before the hint. [...]
Hi Olaf, Starting with Boost 1.35, Boost.MultiIndex ordered indices guarantee that hinted insertion takes place as close as possible to the hint, please take a look at http://www.boost.org/libs/multi_index/doc/release_notes.html#boost_1_35 . But you're right this is not stated in the docs. I'll change that. It'd help if you can file a ticket for the issue so that I don't forget. Thank you, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

Hi Joaquin,
Starting with Boost 1.35, Boost.MultiIndex ordered indices guarantee that hinted insertion takes place as close as possible to the hint, please take a look at http://www.boost.org/libs/multi_index/doc/release_notes.html#boost_1_35 . But what means "as close as possible"? Is "before the hint" closer then "after the hint" by definition? I doubt it. DR233 and the resolution isn't more clear in that respect too and I'm going to raise the question in csc++ if I don't find a clarification elsewhere. boost::intrusive has introduced insert_before (@Ion: the function is nowhere stated in the release notes for 1.41 but I didn't found it in 1.40), which does exactly what I need. However using boost::intrusive is somewhat more difficult (even if for a particular reason I know how to use it ;-)
But you're right this is not stated in the docs. I'll change that. It'd help if you can file a ticket for the issue so that I don't forget. I'll do that.
Best regards Olaf

Hi again, I think I got it. I overread the "prior" in: "t is inserted as close as possible to the position just prior to p." To a certain degree the position described above can be seen as the position between p and its predecessor (if it exists), can't it? Thus boost:multindex complies to N1780(?). Best regards Olaf

Olaf Krzikalla
Hi again,
I think I got it. I overread the "prior" in:
"t is inserted as close as possible to the position just prior to p."
To a certain degree the position described above can be seen as the position between p and its predecessor (if it exists), can't it?
No, it's more general than this: assume we've got a container with elements a1, a2, ... , an, k1, k2, ... , km, b1, b2, ... , bl where k1, ... , km are equivalent (and the rest are not equivalent to these). Put A=[a1,k1), K=[k1,b1), B=[b1,end]. Now if we insert an element equivalent to these in K using hint p, then: * if p is in A, insertion takes place before k1, * if p is in K, insertion takes place before p, * if p is in B, insertion takes place before b1.
Thus boost:multindex complies to N1780(?).
Yes. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

No, it's more general than this: assume we've got a container with elements
a1, a2, ... , an, k1, k2, ... , km, b1, b2, ... , bl
where k1, ... , km are equivalent (and the rest are not equivalent to these). Put A=[a1,k1), K=[k1,b1), B=[b1,end]. Now if we insert an element equivalent to these in K using hint p, then:
* if p is in A, insertion takes place before k1, * if p is in K, insertion takes place before p, * if p is in B, insertion takes place before b1. That was clear to me. However thanks for the example. I can use it to describe the point of my uncertainty: assume our hint points to k2 and we want to insert an element with key k (say kn). If "the position just
Joaquin M Lopez Munoz schrieb: prior to k2" means k1, then it's unclear whether kn is inserted before k1 or after k1 - both positions are equal close to k1. However if "the position just prior to k2" means the position between k1 and k2, then all is well defined and works as intended.
Thus boost:multindex complies to N1780(?). Yes. Wonderful :-)
Best regards Olaf

No, it's more general than this: assume we've got a container with elements
a1, a2, ... , an, k1, k2, ... , km, b1, b2, ... , bl
where k1, ... , km are equivalent (and the rest are not equivalent to these). Put A=[a1,k1), K=[k1,b1), B=[b1,end]. Now if we insert an element equivalent to these in K using hint p, then:
* if p is in A, insertion takes place before k1, * if p is in K, insertion takes place before p, * if p is in B, insertion takes place before b1. That was clear to me. However thanks for the example. I can use it to describe the point of my uncertainty: assume our hint points to k2 and we want to insert an element with key k (say kn). If "the position just
Joaquin M Lopez Munoz schrieb: prior to k2" means k1, then it's unclear whether kn is inserted before k1 or after k1 - both positions are equal close to k1. However if "the position just prior to k2" means the position between k1 and k2, then all is well defined and works as intended.
Thus boost:multindex complies to N1780(?). Yes. Wonderful :-)
Best regards Olaf

Olaf Krzikalla
Joaquin M Lopez Munoz schrieb:
* if p is in A, insertion takes place before k1, * if p is in K, insertion takes place before p, * if p is in B, insertion takes place before b1.
That was clear to me. However thanks for the example. I can use it to describe the point of my uncertainty: assume our hint points to k2 and we want to insert an element with key k (say kn). If "the position just prior to k2" means k1, then it's unclear whether kn is inserted before k1 or after k1 - both positions are equal close to k1. However if "the position just prior to k2" means the position between k1 and k2, then all is well defined and works as intended.
It is the latter --the position between k1 and k2. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

2009/12/18 Joaquin M Lopez Munoz
No, it's more general than this: assume we've got a container with elements
a1, a2, ... , an, k1, k2, ... , km, b1, b2, ... , bl
where k1, ... , km are equivalent (and the rest are not equivalent to these). Put A=[a1,k1), K=[k1,b1), B=[b1,end]. Now if we insert an element equivalent to these in K using hint p, then:
* if p is in A, insertion takes place before k1, * if p is in K, insertion takes place before p, * if p is in B, insertion takes place before b1.
Looking at n3000, only associative containers' 'insert' is specified this way. For 'emplace_hint', it says: equivalent to a.emplace(std::forward<Args>(args)...). [...] Implementations are permitted to ignore the hint. which I think means that the element is placed at the end of the equivalent elements. There are similar definitions for unordered containers' 'insert' with hint and 'emplace_hint'. Presumably this is a defect? Daniel

Daniel James
2009/12/18 Joaquin M Lopez Munoz
: No, it's more general than this: assume we've got a container with elements
a1, a2, ... , an, k1, k2, ... , km, b1, b2, ... , bl
where k1, ... , km are equivalent (and the rest are not equivalent to these). Put A=[a1,k1), K=[k1,b1), B=[b1,end]. Now if we insert an element equivalent to these in K using hint p, then:
* if p is in A, insertion takes place before k1, * if p is in K, insertion takes place before p, * if p is in B, insertion takes place before b1.
Looking at n3000, only associative containers' 'insert' is specified this way. For 'emplace_hint', it says:
equivalent to a.emplace(std::forward<Args>(args)...). [...] Implementations are permitted to ignore the hint.
which I think means that the element is placed at the end of the equivalent elements. There are similar definitions for unordered containers' 'insert' with hint and 'emplace_hint'. Presumably this is a defect?
I think you've spotted a defect in the case of associative containers. As for the unordered associative containers I don't see an issue, since insert in this case does not specify in any case the point of insertion (except to the extent that equivalent elements must stay together.) Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
participants (4)
-
Daniel James
-
Joaquin M Lopez Munoz
-
joaquin@tid.es
-
Olaf Krzikalla