263 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2010 11// <flat_map>12 13// template<class... Args>14// pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);15// template<class... Args>16// pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);17// template<class... Args>18// iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);19// template<class... Args>20// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);21 22#include <flat_map>23#include <cassert>24#include <functional>25#include <deque>26 27#include "MinSequenceContainer.h"28#include "test_macros.h"29#include "../helpers.h"30#include "min_allocator.h"31#include "../../../Emplaceable.h"32 33// Constraints: is_constructible_v<mapped_type, Args...> is true.34template <class M, class... Args>35concept CanTryEmplace = requires(M m, Args&&... args) { m.try_emplace(std::forward<Args>(args)...); };36 37using Map = std::flat_map<Emplaceable, Emplaceable>;38using Iter = typename Map::const_iterator;39static_assert(!CanTryEmplace<Map>);40 41static_assert(CanTryEmplace<Map, const Emplaceable&>);42static_assert(CanTryEmplace<Map, const Emplaceable&, Emplaceable>);43static_assert(CanTryEmplace<Map, const Emplaceable&, int, double>);44static_assert(!CanTryEmplace<Map, const Emplaceable&, const Emplaceable&>);45static_assert(!CanTryEmplace<Map, const Emplaceable&, int>);46 47static_assert(CanTryEmplace<Map, Emplaceable>);48static_assert(CanTryEmplace<Map, Emplaceable, Emplaceable>);49static_assert(CanTryEmplace<Map, Emplaceable, int, double>);50static_assert(!CanTryEmplace<Map, Emplaceable, const Emplaceable&>);51static_assert(!CanTryEmplace<Map, Emplaceable, int>);52 53static_assert(CanTryEmplace<Map, Iter, const Emplaceable&>);54static_assert(CanTryEmplace<Map, Iter, const Emplaceable&, Emplaceable>);55static_assert(CanTryEmplace<Map, Iter, const Emplaceable&, int, double>);56static_assert(!CanTryEmplace<Map, Iter, const Emplaceable&, const Emplaceable&>);57static_assert(!CanTryEmplace<Map, Iter, const Emplaceable&, int>);58 59static_assert(CanTryEmplace<Map, Iter, Emplaceable>);60static_assert(CanTryEmplace<Map, Iter, Emplaceable, Emplaceable>);61static_assert(CanTryEmplace<Map, Iter, Emplaceable, int, double>);62static_assert(!CanTryEmplace<Map, Iter, Emplaceable, const Emplaceable&>);63static_assert(!CanTryEmplace<Map, Iter, Emplaceable, int>);64 65template <class KeyContainer, class ValueContainer>66constexpr void test_ck() {67 using Key = typename KeyContainer::value_type;68 using Value = typename ValueContainer::value_type;69 using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;70 71 { // pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);72 using R = std::pair<typename M::iterator, bool>;73 M m;74 for (int i = 0; i < 20; i += 2)75 m.emplace(i, Moveable(i, (double)i));76 77 assert(m.size() == 10);78 79 Moveable mv1(3, 3.0);80 for (int i = 0; i < 20; i += 2) {81 std::same_as<R> decltype(auto) r = m.try_emplace(i, std::move(mv1));82 assert(m.size() == 10);83 assert(!r.second); // was not inserted84 assert(!mv1.moved()); // was not moved from85 assert(r.first->first == i); // key86 }87 88 std::same_as<R> decltype(auto) r2 = m.try_emplace(-1, std::move(mv1));89 assert(m.size() == 11);90 assert(r2.second); // was inserted91 assert(mv1.moved()); // was moved from92 assert(r2.first->first == -1); // key93 assert(r2.first->second.get() == 3); // value94 95 Moveable mv2(5, 3.0);96 std::same_as<R> decltype(auto) r3 = m.try_emplace(5, std::move(mv2));97 assert(m.size() == 12);98 assert(r3.second); // was inserted99 assert(mv2.moved()); // was moved from100 assert(r3.first->first == 5); // key101 assert(r3.first->second.get() == 5); // value102 103 Moveable mv3(-1, 3.0);104 std::same_as<R> decltype(auto) r4 = m.try_emplace(117, std::move(mv3));105 assert(m.size() == 13);106 assert(r4.second); // was inserted107 assert(mv2.moved()); // was moved from108 assert(r4.first->first == 117); // key109 assert(r4.first->second.get() == -1); // value110 }111 112 { // iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);113 using R = typename M::iterator;114 M m;115 for (int i = 0; i < 20; i += 2)116 m.try_emplace(i, Moveable(i, (double)i));117 assert(m.size() == 10);118 typename M::const_iterator it = m.find(2);119 120 Moveable mv1(3, 3.0);121 for (int i = 0; i < 20; i += 2) {122 std::same_as<R> decltype(auto) r1 = m.try_emplace(it, i, std::move(mv1));123 assert(m.size() == 10);124 assert(!mv1.moved()); // was not moved from125 assert(r1->first == i); // key126 assert(r1->second.get() == i); // value127 }128 129 std::same_as<R> decltype(auto) r2 = m.try_emplace(it, 3, std::move(mv1));130 assert(m.size() == 11);131 assert(mv1.moved()); // was moved from132 assert(r2->first == 3); // key133 assert(r2->second.get() == 3); // value134 }135}136 137template <class KeyContainer, class ValueContainer>138constexpr void test_rk() {139 using Key = typename KeyContainer::value_type;140 using Value = typename ValueContainer::value_type;141 using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;142 143 { // pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);144 using R = std::pair<typename M::iterator, bool>;145 M m;146 for (int i = 0; i < 20; i += 2) {147 m.emplace(Moveable(i, (double)i), Moveable(i + 1, (double)i + 1));148 }149 assert(m.size() == 10);150 151 Moveable mvkey1(2, 2.0);152 Moveable mv1(4, 4.0);153 std::same_as<R> decltype(auto) r1 = m.try_emplace(std::move(mvkey1), std::move(mv1));154 assert(m.size() == 10);155 assert(!r1.second); // was not inserted156 assert(!mv1.moved()); // was not moved from157 assert(!mvkey1.moved()); // was not moved from158 assert(r1.first->first == mvkey1); // key159 160 Moveable mvkey2(3, 3.0);161 std::same_as<R> decltype(auto) r2 = m.try_emplace(std::move(mvkey2), std::move(mv1));162 assert(m.size() == 11);163 assert(r2.second); // was inserted164 assert(mv1.moved()); // was moved from165 assert(mvkey2.moved()); // was moved from166 assert(r2.first->first.get() == 3); // key167 assert(r2.first->second.get() == 4); // value168 }169 170 { // iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);171 using R = typename M::iterator;172 M m;173 for (int i = 0; i < 20; i += 2)174 m.emplace(Moveable(i, (double)i), Moveable(i + 1, (double)i + 1));175 assert(m.size() == 10);176 typename M::const_iterator it = std::next(m.cbegin());177 178 Moveable mvkey1(2, 2.0);179 Moveable mv1(4, 4.0);180 std::same_as<R> decltype(auto) r1 = m.try_emplace(it, std::move(mvkey1), std::move(mv1));181 assert(m.size() == 10);182 assert(!mv1.moved()); // was not moved from183 assert(!mvkey1.moved()); // was not moved from184 assert(r1->first == mvkey1); // key185 186 Moveable mvkey2(3, 3.0);187 std::same_as<R> decltype(auto) r2 = m.try_emplace(it, std::move(mvkey2), std::move(mv1));188 assert(m.size() == 11);189 assert(mv1.moved()); // was moved from190 assert(mvkey2.moved()); // was moved from191 assert(r2->first.get() == 3); // key192 assert(r2->second.get() == 4); // value193 }194}195 196constexpr bool test() {197 test_ck<std::vector<int>, std::vector<Moveable>>();198#ifndef __cpp_lib_constexpr_deque199 if (!TEST_IS_CONSTANT_EVALUATED)200#endif201 {202 test_ck<std::deque<int>, std::vector<Moveable>>();203 test_rk<std::deque<Moveable>, std::vector<Moveable>>();204 }205 test_ck<MinSequenceContainer<int>, MinSequenceContainer<Moveable>>();206 test_ck<std::vector<int, min_allocator<int>>, std::vector<Moveable, min_allocator<Moveable>>>();207 208 test_rk<std::vector<Moveable>, std::vector<Moveable>>();209 test_rk<MinSequenceContainer<Moveable>, MinSequenceContainer<Moveable>>();210 test_rk<std::vector<Moveable, min_allocator<Moveable>>, std::vector<Moveable, min_allocator<Moveable>>>();211 212 if (!TEST_IS_CONSTANT_EVALUATED) {213 {214 auto try_emplace_ck = [](auto& m, auto key_arg, auto value_arg) {215 using M = std::decay_t<decltype(m)>;216 using Key = typename M::key_type;217 const Key key{key_arg};218 m.try_emplace(key, value_arg);219 };220 test_emplace_exception_guarantee(try_emplace_ck);221 }222 223 {224 auto try_emplace_rk = [](auto& m, auto key_arg, auto value_arg) {225 using M = std::decay_t<decltype(m)>;226 using Key = typename M::key_type;227 m.try_emplace(Key{key_arg}, value_arg);228 };229 test_emplace_exception_guarantee(try_emplace_rk);230 }231 232 {233 auto try_emplace_iter_ck = [](auto& m, auto key_arg, auto value_arg) {234 using M = std::decay_t<decltype(m)>;235 using Key = typename M::key_type;236 const Key key{key_arg};237 m.try_emplace(m.begin(), key, value_arg);238 };239 test_emplace_exception_guarantee(try_emplace_iter_ck);240 }241 242 {243 auto try_emplace_iter_rk = [](auto& m, auto key_arg, auto value_arg) {244 using M = std::decay_t<decltype(m)>;245 using Key = typename M::key_type;246 m.try_emplace(m.begin(), Key{key_arg}, value_arg);247 };248 test_emplace_exception_guarantee(try_emplace_iter_rk);249 }250 }251 252 return true;253}254 255int main(int, char**) {256 test();257#if TEST_STD_VER >= 26258 static_assert(test());259#endif260 261 return 0;262}263