//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // // template // pair try_emplace(const key_type& k, Args&&... args); // template // pair try_emplace(key_type&& k, Args&&... args); // template // iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); // template // iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); #include #include #include #include #include "MinSequenceContainer.h" #include "test_macros.h" #include "../helpers.h" #include "min_allocator.h" #include "../../../Emplaceable.h" // Constraints: is_constructible_v is true. template concept CanTryEmplace = requires(M m, Args&&... args) { m.try_emplace(std::forward(args)...); }; using Map = std::flat_map; using Iter = typename Map::const_iterator; static_assert(!CanTryEmplace); static_assert(CanTryEmplace); static_assert(CanTryEmplace); static_assert(CanTryEmplace); static_assert(!CanTryEmplace); static_assert(!CanTryEmplace); static_assert(CanTryEmplace); static_assert(CanTryEmplace); static_assert(CanTryEmplace); static_assert(!CanTryEmplace); static_assert(!CanTryEmplace); static_assert(CanTryEmplace); static_assert(CanTryEmplace); static_assert(CanTryEmplace); static_assert(!CanTryEmplace); static_assert(!CanTryEmplace); static_assert(CanTryEmplace); static_assert(CanTryEmplace); static_assert(CanTryEmplace); static_assert(!CanTryEmplace); static_assert(!CanTryEmplace); template constexpr void test_ck() { using Key = typename KeyContainer::value_type; using Value = typename ValueContainer::value_type; using M = std::flat_map, KeyContainer, ValueContainer>; { // pair try_emplace(const key_type& k, Args&&... args); using R = std::pair; M m; for (int i = 0; i < 20; i += 2) m.emplace(i, Moveable(i, (double)i)); assert(m.size() == 10); Moveable mv1(3, 3.0); for (int i = 0; i < 20; i += 2) { std::same_as decltype(auto) r = m.try_emplace(i, std::move(mv1)); assert(m.size() == 10); assert(!r.second); // was not inserted assert(!mv1.moved()); // was not moved from assert(r.first->first == i); // key } std::same_as decltype(auto) r2 = m.try_emplace(-1, std::move(mv1)); assert(m.size() == 11); assert(r2.second); // was inserted assert(mv1.moved()); // was moved from assert(r2.first->first == -1); // key assert(r2.first->second.get() == 3); // value Moveable mv2(5, 3.0); std::same_as decltype(auto) r3 = m.try_emplace(5, std::move(mv2)); assert(m.size() == 12); assert(r3.second); // was inserted assert(mv2.moved()); // was moved from assert(r3.first->first == 5); // key assert(r3.first->second.get() == 5); // value Moveable mv3(-1, 3.0); std::same_as decltype(auto) r4 = m.try_emplace(117, std::move(mv3)); assert(m.size() == 13); assert(r4.second); // was inserted assert(mv2.moved()); // was moved from assert(r4.first->first == 117); // key assert(r4.first->second.get() == -1); // value } { // iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); using R = typename M::iterator; M m; for (int i = 0; i < 20; i += 2) m.try_emplace(i, Moveable(i, (double)i)); assert(m.size() == 10); typename M::const_iterator it = m.find(2); Moveable mv1(3, 3.0); for (int i = 0; i < 20; i += 2) { std::same_as decltype(auto) r1 = m.try_emplace(it, i, std::move(mv1)); assert(m.size() == 10); assert(!mv1.moved()); // was not moved from assert(r1->first == i); // key assert(r1->second.get() == i); // value } std::same_as decltype(auto) r2 = m.try_emplace(it, 3, std::move(mv1)); assert(m.size() == 11); assert(mv1.moved()); // was moved from assert(r2->first == 3); // key assert(r2->second.get() == 3); // value } } template constexpr void test_rk() { using Key = typename KeyContainer::value_type; using Value = typename ValueContainer::value_type; using M = std::flat_map, KeyContainer, ValueContainer>; { // pair try_emplace(key_type&& k, Args&&... args); using R = std::pair; M m; for (int i = 0; i < 20; i += 2) { m.emplace(Moveable(i, (double)i), Moveable(i + 1, (double)i + 1)); } assert(m.size() == 10); Moveable mvkey1(2, 2.0); Moveable mv1(4, 4.0); std::same_as decltype(auto) r1 = m.try_emplace(std::move(mvkey1), std::move(mv1)); assert(m.size() == 10); assert(!r1.second); // was not inserted assert(!mv1.moved()); // was not moved from assert(!mvkey1.moved()); // was not moved from assert(r1.first->first == mvkey1); // key Moveable mvkey2(3, 3.0); std::same_as decltype(auto) r2 = m.try_emplace(std::move(mvkey2), std::move(mv1)); assert(m.size() == 11); assert(r2.second); // was inserted assert(mv1.moved()); // was moved from assert(mvkey2.moved()); // was moved from assert(r2.first->first.get() == 3); // key assert(r2.first->second.get() == 4); // value } { // iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); using R = typename M::iterator; M m; for (int i = 0; i < 20; i += 2) m.emplace(Moveable(i, (double)i), Moveable(i + 1, (double)i + 1)); assert(m.size() == 10); typename M::const_iterator it = std::next(m.cbegin()); Moveable mvkey1(2, 2.0); Moveable mv1(4, 4.0); std::same_as decltype(auto) r1 = m.try_emplace(it, std::move(mvkey1), std::move(mv1)); assert(m.size() == 10); assert(!mv1.moved()); // was not moved from assert(!mvkey1.moved()); // was not moved from assert(r1->first == mvkey1); // key Moveable mvkey2(3, 3.0); std::same_as decltype(auto) r2 = m.try_emplace(it, std::move(mvkey2), std::move(mv1)); assert(m.size() == 11); assert(mv1.moved()); // was moved from assert(mvkey2.moved()); // was moved from assert(r2->first.get() == 3); // key assert(r2->second.get() == 4); // value } } constexpr bool test() { test_ck, std::vector>(); #ifndef __cpp_lib_constexpr_deque if (!TEST_IS_CONSTANT_EVALUATED) #endif { test_ck, std::vector>(); test_rk, std::vector>(); } test_ck, MinSequenceContainer>(); test_ck>, std::vector>>(); test_rk, std::vector>(); test_rk, MinSequenceContainer>(); test_rk>, std::vector>>(); if (!TEST_IS_CONSTANT_EVALUATED) { { auto try_emplace_ck = [](auto& m, auto key_arg, auto value_arg) { using M = std::decay_t; using Key = typename M::key_type; const Key key{key_arg}; m.try_emplace(key, value_arg); }; test_emplace_exception_guarantee(try_emplace_ck); } { auto try_emplace_rk = [](auto& m, auto key_arg, auto value_arg) { using M = std::decay_t; using Key = typename M::key_type; m.try_emplace(Key{key_arg}, value_arg); }; test_emplace_exception_guarantee(try_emplace_rk); } { auto try_emplace_iter_ck = [](auto& m, auto key_arg, auto value_arg) { using M = std::decay_t; using Key = typename M::key_type; const Key key{key_arg}; m.try_emplace(m.begin(), key, value_arg); }; test_emplace_exception_guarantee(try_emplace_iter_ck); } { auto try_emplace_iter_rk = [](auto& m, auto key_arg, auto value_arg) { using M = std::decay_t; using Key = typename M::key_type; m.try_emplace(m.begin(), Key{key_arg}, value_arg); }; test_emplace_exception_guarantee(try_emplace_iter_rk); } } return true; } int main(int, char**) { test(); #if TEST_STD_VER >= 26 static_assert(test()); #endif return 0; }