Skip to content

Commit 73d91c5

Browse files
committed
Implement transparent insert_or_assign (C++26) for map.
1 parent c7a3d86 commit 73d91c5

File tree

3 files changed

+182
-112
lines changed

3 files changed

+182
-112
lines changed

include/boost/container/detail/tree.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,10 +1115,10 @@ class tree
11151115
std::pair<iterator, bool> insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj)
11161116
{
11171117
insert_commit_data data;
1118-
const key_type & k = key; //Support emulated rvalue references
1118+
const typename remove_cvref<KeyType>::type & k = key; //Support emulated rvalue references
11191119
std::pair<iiterator, bool> ret =
1120-
hint == const_iterator() ? this->icont().insert_unique_check(k, data)
1121-
: this->icont().insert_unique_check(hint.get(), k, data);
1120+
hint == const_iterator() ? this->icont().insert_unique_check(k, KeyNodeCompare(key_comp()), data)
1121+
: this->icont().insert_unique_check(hint.get(), k, KeyNodeCompare(key_comp()), data);
11221122
if(ret.second){
11231123
ret.first = this->priv_insert_or_assign_commit(boost::forward<KeyType>(key), boost::forward<M>(obj), data);
11241124
}

include/boost/container/map.hpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,31 @@ class map
611611
inline std::pair<iterator, bool> insert_or_assign(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj)
612612
{ return this->base_t::insert_or_assign(const_iterator(), ::boost::move(k), ::boost::forward<M>(obj)); }
613613

614+
//! <b>Requires</b>: This overload is available only if key_compare::is_transparent exists.
615+
//!
616+
//! <b>Effects</b>: If a key equivalent to k already exists in the container, assigns forward<M>(obj)
617+
//! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value
618+
//! as if by insert, constructing it from value_type(k, move(obj)).
619+
//!
620+
//! No iterators or references are invalidated. If the insertion is successful, pointers and references
621+
//! to the element obtained while it is held in the node handle are invalidated, and pointers and
622+
//! references obtained to that element before it was extracted become valid.
623+
//!
624+
//! <b>Returns</b>: The bool component is true if the insertion took place and false if the assignment
625+
//! took place. The iterator component is pointing at the element that was inserted or updated.
626+
//!
627+
//! <b>Complexity</b>: Logarithmic in the size of the container.
628+
template <class K, class M>
629+
630+
BOOST_CONTAINER_DOC1ST
631+
( std::pair<iterator BOOST_MOVE_I bool>
632+
, typename dtl::enable_if_transparent< key_compare
633+
BOOST_MOVE_I K
634+
BOOST_MOVE_I std::pair<iterator BOOST_MOVE_I bool>
635+
>::type) //transparent
636+
insert_or_assign(BOOST_FWD_REF(K) k, BOOST_FWD_REF(M) obj)
637+
{ return this->base_t::insert_or_assign(const_iterator(), ::boost::forward<K>(k), ::boost::forward<M>(obj)); }
638+
614639
//! <b>Effects</b>: If a key equivalent to k already exists in the container, assigns forward<M>(obj)
615640
//! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value
616641
//! as if by insert, constructing it from value_type(k, forward<M>(obj)) and the new element
@@ -645,6 +670,31 @@ class map
645670
inline iterator insert_or_assign(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj)
646671
{ return this->base_t::insert_or_assign(hint, ::boost::move(k), ::boost::forward<M>(obj)).first; }
647672

673+
//! <b>Requires</b>: This overload is available only if key_compare::is_transparent exists.
674+
//!
675+
//! <b>Effects</b>: If a key equivalent to k already exists in the container, assigns forward<M>(obj)
676+
//! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value
677+
//! as if by insert, constructing it from value_type(k, move(obj)) and the new element
678+
//! to the container as close as possible to the position just before hint.
679+
//!
680+
//! No iterators or references are invalidated. If the insertion is successful, pointers and references
681+
//! to the element obtained while it is held in the node handle are invalidated, and pointers and
682+
//! references obtained to that element before it was extracted become valid.
683+
//!
684+
//! <b>Returns</b>: The returned iterator points to the map element whose key is equivalent to k.
685+
//!
686+
//! <b>Complexity</b>: Logarithmic in the size of the container in general, but amortized constant if
687+
//! the new element is inserted just before hint.
688+
template <class K, class M>
689+
BOOST_CONTAINER_DOC1ST
690+
( iterator
691+
, typename dtl::enable_if_transparent< key_compare
692+
BOOST_MOVE_I K
693+
BOOST_MOVE_I iterator
694+
>::type) //transparent
695+
insert_or_assign(const_iterator hint, BOOST_FWD_REF(K) k, BOOST_FWD_REF(M) obj)
696+
{ return this->base_t::insert_or_assign(hint, ::boost::forward<K>(k), ::boost::forward<M>(obj)).first; }
697+
648698
//! <b>Returns</b>: A reference to the element whose key is equivalent to x.
649699
//! Throws: An exception object of type out_of_range if no such element is present.
650700
//! <b>Complexity</b>: logarithmic.

test/map_test.cpp

Lines changed: 129 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -261,115 +261,135 @@ void test_merge_from_different_comparison()
261261

262262
bool test_heterogeneous_lookups()
263263
{
264-
typedef map<int, char, less_transparent> map_t;
265-
typedef multimap<int, char, less_transparent> mmap_t;
266-
typedef map_t::value_type value_type;
267-
268-
map_t map1;
269-
mmap_t mmap1;
270-
271-
const map_t &cmap1 = map1;
272-
const mmap_t &cmmap1 = mmap1;
273-
274-
if(!map1.insert_or_assign(1, 'a').second)
275-
return false;
276-
if( map1.insert_or_assign(1, 'b').second)
277-
return false;
278-
if(!map1.insert_or_assign(2, 'c').second)
279-
return false;
280-
if( map1.insert_or_assign(2, 'd').second)
281-
return false;
282-
if(!map1.insert_or_assign(3, 'e').second)
283-
return false;
284-
285-
if(map1.insert_or_assign(1, 'a').second)
286-
return false;
287-
if(map1.insert_or_assign(1, 'b').second)
288-
return false;
289-
if(map1.insert_or_assign(2, 'c').second)
290-
return false;
291-
if(map1.insert_or_assign(2, 'd').second)
292-
return false;
293-
if(map1.insert_or_assign(3, 'e').second)
294-
return false;
295-
296-
mmap1.insert(value_type(1, 'a'));
297-
mmap1.insert(value_type(1, 'b'));
298-
mmap1.insert(value_type(2, 'c'));
299-
mmap1.insert(value_type(2, 'd'));
300-
mmap1.insert(value_type(3, 'e'));
301-
302-
const test::non_copymovable_int find_me(2);
303-
304-
//find
305-
if(map1.find(find_me)->second != 'd')
306-
return false;
307-
if(cmap1.find(find_me)->second != 'd')
308-
return false;
309-
if(mmap1.find(find_me)->second != 'c')
310-
return false;
311-
if(cmmap1.find(find_me)->second != 'c')
312-
return false;
313-
314-
//count
315-
if(map1.count(find_me) != 1)
316-
return false;
317-
if(cmap1.count(find_me) != 1)
318-
return false;
319-
if(mmap1.count(find_me) != 2)
320-
return false;
321-
if(cmmap1.count(find_me) != 2)
322-
return false;
323-
324-
//contains
325-
if(!map1.contains(find_me))
326-
return false;
327-
if(!cmap1.contains(find_me))
328-
return false;
329-
if(!mmap1.contains(find_me))
330-
return false;
331-
if(!cmmap1.contains(find_me))
332-
return false;
333-
334-
//lower_bound
335-
if(map1.lower_bound(find_me)->second != 'd')
336-
return false;
337-
if(cmap1.lower_bound(find_me)->second != 'd')
338-
return false;
339-
if(mmap1.lower_bound(find_me)->second != 'c')
340-
return false;
341-
if(cmmap1.lower_bound(find_me)->second != 'c')
342-
return false;
343-
344-
//upper_bound
345-
if(map1.upper_bound(find_me)->second != 'e')
346-
return false;
347-
if(cmap1.upper_bound(find_me)->second != 'e')
348-
return false;
349-
if(mmap1.upper_bound(find_me)->second != 'e')
350-
return false;
351-
if(cmmap1.upper_bound(find_me)->second != 'e')
352-
return false;
353-
354-
//equal_range
355-
if(map1.equal_range(find_me).first->second != 'd')
356-
return false;
357-
if(cmap1.equal_range(find_me).second->second != 'e')
358-
return false;
359-
if(mmap1.equal_range(find_me).first->second != 'c')
360-
return false;
361-
if(cmmap1.equal_range(find_me).second->second != 'e')
362-
return false;
363-
364-
//erase
365-
if (map1.erase(find_me) != 1)
366-
return false;
367-
if (map1.erase(find_me) != 0)
368-
return false;
369-
if (mmap1.erase(find_me) != 2)
370-
return false;
371-
if (mmap1.erase(find_me) != 0)
372-
return false;
264+
{
265+
typedef map<int, char, less_transparent> map_t;
266+
typedef multimap<int, char, less_transparent> mmap_t;
267+
typedef map_t::value_type value_type;
268+
269+
map_t map1;
270+
mmap_t mmap1;
271+
272+
const map_t &cmap1 = map1;
273+
const mmap_t &cmmap1 = mmap1;
274+
275+
if(!map1.insert_or_assign(1, 'a').second)
276+
return false;
277+
if( map1.insert_or_assign(1, 'b').second)
278+
return false;
279+
if(!map1.insert_or_assign(2, 'c').second)
280+
return false;
281+
if( map1.insert_or_assign(2, 'd').second)
282+
return false;
283+
if(!map1.insert_or_assign(3, 'e').second)
284+
return false;
285+
286+
if(map1.insert_or_assign(1, 'a').second)
287+
return false;
288+
if(map1.insert_or_assign(1, 'b').second)
289+
return false;
290+
if(map1.insert_or_assign(2, 'c').second)
291+
return false;
292+
if(map1.insert_or_assign(2, 'd').second)
293+
return false;
294+
if(map1.insert_or_assign(3, 'e').second)
295+
return false;
296+
297+
mmap1.insert(value_type(1, 'a'));
298+
mmap1.insert(value_type(1, 'b'));
299+
mmap1.insert(value_type(2, 'c'));
300+
mmap1.insert(value_type(2, 'd'));
301+
mmap1.insert(value_type(3, 'e'));
302+
303+
const test::non_copymovable_int find_me(2);
304+
305+
//find
306+
if(map1.find(find_me)->second != 'd')
307+
return false;
308+
if(cmap1.find(find_me)->second != 'd')
309+
return false;
310+
if(mmap1.find(find_me)->second != 'c')
311+
return false;
312+
if(cmmap1.find(find_me)->second != 'c')
313+
return false;
314+
315+
//count
316+
if(map1.count(find_me) != 1)
317+
return false;
318+
if(cmap1.count(find_me) != 1)
319+
return false;
320+
if(mmap1.count(find_me) != 2)
321+
return false;
322+
if(cmmap1.count(find_me) != 2)
323+
return false;
324+
325+
//contains
326+
if(!map1.contains(find_me))
327+
return false;
328+
if(!cmap1.contains(find_me))
329+
return false;
330+
if(!mmap1.contains(find_me))
331+
return false;
332+
if(!cmmap1.contains(find_me))
333+
return false;
334+
335+
//lower_bound
336+
if(map1.lower_bound(find_me)->second != 'd')
337+
return false;
338+
if(cmap1.lower_bound(find_me)->second != 'd')
339+
return false;
340+
if(mmap1.lower_bound(find_me)->second != 'c')
341+
return false;
342+
if(cmmap1.lower_bound(find_me)->second != 'c')
343+
return false;
344+
345+
//upper_bound
346+
if(map1.upper_bound(find_me)->second != 'e')
347+
return false;
348+
if(cmap1.upper_bound(find_me)->second != 'e')
349+
return false;
350+
if(mmap1.upper_bound(find_me)->second != 'e')
351+
return false;
352+
if(cmmap1.upper_bound(find_me)->second != 'e')
353+
return false;
354+
355+
//equal_range
356+
if(map1.equal_range(find_me).first->second != 'd')
357+
return false;
358+
if(cmap1.equal_range(find_me).second->second != 'e')
359+
return false;
360+
if(mmap1.equal_range(find_me).first->second != 'c')
361+
return false;
362+
if(cmmap1.equal_range(find_me).second->second != 'e')
363+
return false;
364+
365+
//erase
366+
if (map1.erase(find_me) != 1)
367+
return false;
368+
if (map1.erase(find_me) != 0)
369+
return false;
370+
if (mmap1.erase(find_me) != 2)
371+
return false;
372+
if (mmap1.erase(find_me) != 0)
373+
return false;
374+
}
375+
{
376+
typedef map<test::movable_int, char, less_transparent> map_t;
377+
378+
map_t map1;
379+
380+
//insert_or_assign
381+
if(!map1.insert_or_assign(1, 'e').second)
382+
return false;
383+
if(map1.insert_or_assign(1, 'b').second)
384+
return false;
385+
386+
//insert_or_assign with hint
387+
if(map1.find(2) != map1.end())
388+
return false;
389+
map_t::iterator i = map1.insert_or_assign(map1.begin(), 2, 'e');
390+
if(i != map1.insert_or_assign(map1.end(), 2, 'b'))
391+
return false;
392+
}
373393
return true;
374394
}
375395

0 commit comments

Comments
 (0)