Skip to content

Commit f394ffc

Browse files
committed
Implement transparent insert_or_assign (C++26) for flat_map
1 parent ade3238 commit f394ffc

File tree

3 files changed

+188
-113
lines changed

3 files changed

+188
-113
lines changed

include/boost/container/detail/flat_tree.hpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,7 +1134,7 @@ class flat_tree
11341134
template<class KeyType, class M>
11351135
std::pair<iterator, bool> insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj)
11361136
{
1137-
const key_type& k = key;
1137+
const typename remove_cvref<KeyType>::type & k = key; //Support emulated rvalue references
11381138
std::pair<iterator,bool> ret;
11391139
insert_commit_data data;
11401140
ret.second = hint == const_iterator()
@@ -1583,20 +1583,23 @@ class flat_tree
15831583
}
15841584
}
15851585

1586+
template<class K>
15861587
bool priv_insert_unique_prepare
1587-
(const_iterator b, const_iterator e, const key_type& k, insert_commit_data &commit_data)
1588+
(const_iterator b, const_iterator e, const K& k, insert_commit_data &commit_data)
15881589
{
15891590
const key_compare &key_cmp = this->priv_key_comp();
15901591
commit_data.position = this->priv_lower_bound(b, e, k);
15911592
return commit_data.position == e || key_cmp(k, KeyOfValue()(*commit_data.position));
15921593
}
15931594

1595+
template<class K>
15941596
inline bool priv_insert_unique_prepare
1595-
(const key_type& k, insert_commit_data &commit_data)
1597+
(const K& k, insert_commit_data &commit_data)
15961598
{ return this->priv_insert_unique_prepare(this->cbegin(), this->cend(), k, commit_data); }
15971599

1600+
template<class K>
15981601
bool priv_insert_unique_prepare
1599-
(const_iterator pos, const key_type& k, insert_commit_data &commit_data)
1602+
(const_iterator pos, const K& k, insert_commit_data &commit_data)
16001603
{
16011604
//N1780. Props to Howard Hinnant!
16021605
//To insert k at pos:

include/boost/container/flat_map.hpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,31 @@ class flat_map
831831
);
832832
}
833833

834+
//! <b>Requires</b>: This overload is available only if key_compare::is_transparent exists.
835+
//!
836+
//! <b>Effects</b>: If a key equivalent to k already exists in the container, assigns forward<M>(obj)
837+
//! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value
838+
//! as if by insert, constructing it from value_type(k, move(obj)).
839+
//!
840+
//! <b>Returns</b>: The bool component is true if the insertion took place and false if the assignment
841+
//! took place. The iterator component is pointing at the element that was inserted or updated.
842+
//!
843+
//! <b>Complexity</b>: Logarithmic in the size of the container.
844+
template <class K, class M>
845+
BOOST_CONTAINER_DOC1ST
846+
( std::pair<iterator BOOST_MOVE_I bool>
847+
, typename dtl::enable_if_transparent< key_compare
848+
BOOST_MOVE_I K
849+
BOOST_MOVE_I std::pair<iterator BOOST_MOVE_I bool>
850+
>::type) //transparent
851+
insert_or_assign(BOOST_FWD_REF(K) k, BOOST_FWD_REF(M) obj)
852+
{
853+
return dtl::force_copy< std::pair<iterator, bool> >
854+
(this->m_flat_tree.insert_or_assign
855+
( impl_const_iterator(), ::boost::forward<K>(k), ::boost::forward<M>(obj))
856+
);
857+
}
858+
834859
//! Effects: If a key equivalent to k already exists in the container, assigns forward<M>(obj)
835860
//! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value
836861
//! as if by insert, constructing it from value_type(k, forward<M>(obj)) and the new element
@@ -869,6 +894,33 @@ class flat_map
869894
);
870895
}
871896

897+
//! <b>Requires</b>: This overload is available only if key_compare::is_transparent exists.
898+
//!
899+
//! <b>Effects</b>: If a key equivalent to k already exists in the container, assigns forward<M>(obj)
900+
//! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value
901+
//! as if by insert, constructing it from value_type(k, move(obj)) and the new element
902+
//! to the container as close as possible to the position just before hint.
903+
//!
904+
//! <b>Returns</b>: The returned iterator points to the map element whose key is equivalent to k.
905+
//!
906+
//! <b>Complexity</b>: Logarithmic in the size of the container in general, but amortized constant if
907+
//! the new element is inserted just before hint.
908+
template <class K, class M>
909+
BOOST_CONTAINER_DOC1ST
910+
( iterator
911+
, typename dtl::enable_if_transparent< key_compare
912+
BOOST_MOVE_I K
913+
BOOST_MOVE_I iterator
914+
>::type) //transparent
915+
insert_or_assign(const_iterator hint, BOOST_FWD_REF(K) k, BOOST_FWD_REF(M) obj)
916+
{
917+
return dtl::force_copy<iterator>
918+
(this->m_flat_tree.insert_or_assign
919+
( dtl::force_copy<impl_const_iterator>(hint)
920+
, ::boost::forward<K>(k), ::boost::forward<M>(obj)).first
921+
);
922+
}
923+
872924
//! @copydoc ::boost::container::flat_set::nth(size_type)
873925
BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline
874926
iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW

test/flat_map_test.cpp

Lines changed: 129 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -277,116 +277,136 @@ struct get_real_stored_allocator<flat_multimap<Key, T, Compare, Allocator> >
277277
bool test_heterogeneous_lookups()
278278
{
279279
BOOST_CONTAINER_STATIC_ASSERT((dtl::is_transparent<less_transparent>::value));
280-
BOOST_CONTAINER_STATIC_ASSERT(!(dtl::is_transparent<std::less<int> >::value));
281-
typedef flat_map<int, char, less_transparent> map_t;
282-
typedef flat_multimap<int, char, less_transparent> mmap_t;
283-
typedef map_t::value_type value_type;
284-
285-
map_t map1;
286-
mmap_t mmap1;
287-
288-
const map_t &cmap1 = map1;
289-
const mmap_t &cmmap1 = mmap1;
290-
291-
if(!map1.insert_or_assign(1, 'a').second)
292-
return false;
293-
if( map1.insert_or_assign(1, 'b').second)
294-
return false;
295-
if(!map1.insert_or_assign(2, 'c').second)
296-
return false;
297-
if( map1.insert_or_assign(2, 'd').second)
298-
return false;
299-
if(!map1.insert_or_assign(3, 'e').second)
300-
return false;
301-
302-
if(map1.insert_or_assign(1, 'a').second)
303-
return false;
304-
if(map1.insert_or_assign(1, 'b').second)
305-
return false;
306-
if(map1.insert_or_assign(2, 'c').second)
307-
return false;
308-
if(map1.insert_or_assign(2, 'd').second)
309-
return false;
310-
if(map1.insert_or_assign(3, 'e').second)
311-
return false;
312-
313-
mmap1.insert(value_type(1, 'a'));
314-
mmap1.insert(value_type(1, 'b'));
315-
mmap1.insert(value_type(2, 'c'));
316-
mmap1.insert(value_type(2, 'd'));
317-
mmap1.insert(value_type(3, 'e'));
318-
319-
const test::non_copymovable_int find_me(2);
320-
321-
//find
322-
if(map1.find(find_me)->second != 'd')
323-
return false;
324-
if(cmap1.find(find_me)->second != 'd')
325-
return false;
326-
if(mmap1.find(find_me)->second != 'c')
327-
return false;
328-
if(cmmap1.find(find_me)->second != 'c')
329-
return false;
330-
331-
//count
332-
if(map1.count(find_me) != 1)
333-
return false;
334-
if(cmap1.count(find_me) != 1)
335-
return false;
336-
if(mmap1.count(find_me) != 2)
337-
return false;
338-
if(cmmap1.count(find_me) != 2)
339-
return false;
340-
341-
//contains
342-
if(!map1.contains(find_me))
343-
return false;
344-
if(!cmap1.contains(find_me))
345-
return false;
346-
if(!mmap1.contains(find_me))
347-
return false;
348-
if(!cmmap1.contains(find_me))
349-
return false;
350-
351-
//lower_bound
352-
if(map1.lower_bound(find_me)->second != 'd')
353-
return false;
354-
if(cmap1.lower_bound(find_me)->second != 'd')
355-
return false;
356-
if(mmap1.lower_bound(find_me)->second != 'c')
357-
return false;
358-
if(cmmap1.lower_bound(find_me)->second != 'c')
359-
return false;
360-
361-
//upper_bound
362-
if(map1.upper_bound(find_me)->second != 'e')
363-
return false;
364-
if(cmap1.upper_bound(find_me)->second != 'e')
365-
return false;
366-
if(mmap1.upper_bound(find_me)->second != 'e')
367-
return false;
368-
if(cmmap1.upper_bound(find_me)->second != 'e')
369-
return false;
370-
371-
//equal_range
372-
if(map1.equal_range(find_me).first->second != 'd')
373-
return false;
374-
if(cmap1.equal_range(find_me).second->second != 'e')
375-
return false;
376-
if(mmap1.equal_range(find_me).first->second != 'c')
377-
return false;
378-
if(cmmap1.equal_range(find_me).second->second != 'e')
379-
return false;
280+
{
281+
typedef flat_map<int, char, less_transparent> map_t;
282+
typedef flat_multimap<int, char, less_transparent> mmap_t;
283+
typedef map_t::value_type value_type;
284+
285+
map_t map1;
286+
mmap_t mmap1;
287+
288+
const map_t &cmap1 = map1;
289+
const mmap_t &cmmap1 = mmap1;
290+
291+
if(!map1.insert_or_assign(1, 'a').second)
292+
return false;
293+
if( map1.insert_or_assign(1, 'b').second)
294+
return false;
295+
if(!map1.insert_or_assign(2, 'c').second)
296+
return false;
297+
if( map1.insert_or_assign(2, 'd').second)
298+
return false;
299+
if(!map1.insert_or_assign(3, 'e').second)
300+
return false;
301+
302+
if(map1.insert_or_assign(1, 'a').second)
303+
return false;
304+
if(map1.insert_or_assign(1, 'b').second)
305+
return false;
306+
if(map1.insert_or_assign(2, 'c').second)
307+
return false;
308+
if(map1.insert_or_assign(2, 'd').second)
309+
return false;
310+
if(map1.insert_or_assign(3, 'e').second)
311+
return false;
312+
313+
mmap1.insert(value_type(1, 'a'));
314+
mmap1.insert(value_type(1, 'b'));
315+
mmap1.insert(value_type(2, 'c'));
316+
mmap1.insert(value_type(2, 'd'));
317+
mmap1.insert(value_type(3, 'e'));
318+
319+
const test::non_copymovable_int find_me(2);
320+
321+
//find
322+
if(map1.find(find_me)->second != 'd')
323+
return false;
324+
if(cmap1.find(find_me)->second != 'd')
325+
return false;
326+
if(mmap1.find(find_me)->second != 'c')
327+
return false;
328+
if(cmmap1.find(find_me)->second != 'c')
329+
return false;
330+
331+
//count
332+
if(map1.count(find_me) != 1)
333+
return false;
334+
if(cmap1.count(find_me) != 1)
335+
return false;
336+
if(mmap1.count(find_me) != 2)
337+
return false;
338+
if(cmmap1.count(find_me) != 2)
339+
return false;
340+
341+
//contains
342+
if(!map1.contains(find_me))
343+
return false;
344+
if(!cmap1.contains(find_me))
345+
return false;
346+
if(!mmap1.contains(find_me))
347+
return false;
348+
if(!cmmap1.contains(find_me))
349+
return false;
350+
351+
//lower_bound
352+
if(map1.lower_bound(find_me)->second != 'd')
353+
return false;
354+
if(cmap1.lower_bound(find_me)->second != 'd')
355+
return false;
356+
if(mmap1.lower_bound(find_me)->second != 'c')
357+
return false;
358+
if(cmmap1.lower_bound(find_me)->second != 'c')
359+
return false;
360+
361+
//upper_bound
362+
if(map1.upper_bound(find_me)->second != 'e')
363+
return false;
364+
if(cmap1.upper_bound(find_me)->second != 'e')
365+
return false;
366+
if(mmap1.upper_bound(find_me)->second != 'e')
367+
return false;
368+
if(cmmap1.upper_bound(find_me)->second != 'e')
369+
return false;
370+
371+
//equal_range
372+
if(map1.equal_range(find_me).first->second != 'd')
373+
return false;
374+
if(cmap1.equal_range(find_me).second->second != 'e')
375+
return false;
376+
if(mmap1.equal_range(find_me).first->second != 'c')
377+
return false;
378+
if(cmmap1.equal_range(find_me).second->second != 'e')
379+
return false;
380+
381+
//erase
382+
if (map1.erase(find_me) != 1)
383+
return false;
384+
if (map1.erase(find_me) != 0)
385+
return false;
386+
if (mmap1.erase(find_me) != 2)
387+
return false;
388+
if (mmap1.erase(find_me) != 0)
389+
return false;
390+
}
391+
{
392+
typedef flat_map<test::movable_int, char, less_transparent> map_t;
393+
394+
map_t map1;
395+
396+
//insert_or_assign
397+
if(!map1.insert_or_assign(1, 'e').second)
398+
return false;
399+
if(map1.insert_or_assign(1, 'b').second)
400+
return false;
401+
402+
//insert_or_assign with hint
403+
if(map1.find(2) != map1.end())
404+
return false;
405+
map_t::iterator i = map1.insert_or_assign(map1.begin(), 2, 'e');
406+
if(i != map1.insert_or_assign(map1.end(), 2, 'b'))
407+
return false;
408+
}
380409

381-
//erase
382-
if (map1.erase(find_me) != 1)
383-
return false;
384-
if (map1.erase(find_me) != 0)
385-
return false;
386-
if (mmap1.erase(find_me) != 2)
387-
return false;
388-
if (mmap1.erase(find_me) != 0)
389-
return false;
390410
return true;
391411
}
392412

0 commit comments

Comments
 (0)