blob: 56db9902b39a7597e9523432cf7bfcdbf667a0ae [file] [log] [blame]
// { dg-do run { target c++26 } }
#include <map>
#include <string>
#include <string_view>
#include <utility>
#include <compare>
#include <cstring>
#include <testsuite_hooks.h>
struct Y;
struct Z;
struct X {
std::string s;
X(std::string_view str) : s(str) {}
X(Y&&);
X(const Y&);
X(Z&&);
X(const Z&);
friend auto operator<=>(X const& a, X const& b) = default;
};
struct Y {
std::string s;
Y() = default;
Y(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
Y(const Y& y) = default;
Y& operator=(Y&& y) { s = std::move(y.s); y.s.clear(); return *this; }
Y& operator=(const Y& y) = default;
Y(std::string_view sv) : s(sv) {}
Y(int n) : s(std::string(n, 'a')) {}
Y(const Y& a, const Y& b) : s(a.s + "1" + b.s) { }
Y(const Y& a, Y&& b) : s(a.s + "2" + b.s) { b.s.clear(); }
Y(Y&& a, const Y& b) : s(a.s + "3" + b.s) { a.s.clear(); }
Y(Y&& a, Y&& b) : s(a.s + "4" + b.s) { a.s.clear(), b.s.clear(); }
friend auto operator<=>(Y const& a, Y const& b) = default;
friend auto operator<=>(X const& a, Y const& b) { return a.s <=> b.s; }
};
X::X(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
X::X(const Y& y) : s(y.s) {}
using cmp = std::less<void>;
void test_at()
{
std::map<X, Y, cmp> amap{cmp{}};
amap.insert( {{Y{"abc"}, 1},
{Y{"dee"}, 2}, {Y{"def"}, 3}, {Y{"deg"}, 4},
{Y{"ghi"}, 5}});
Y y{"def"};
try
{
VERIFY(3 == amap.at(y));
VERIFY(amap.size() == 5);
VERIFY(4 == (amap.at(std::move(y)) = 4));
VERIFY(amap.size() == 5);
VERIFY(y.s.size() == 3); // not moved from
}
catch(...) { VERIFY(false); }
try
{
amap.at(Y{"dea"}) = 4;
VERIFY(false); // Should have thrown.
}
catch (std::out_of_range&) { VERIFY(amap.size() == 5); }
catch (...) { VERIFY(false); } // Wrong exception.
auto const& amapr{amap};
Y z{"deh"};
try
{
amapr.at(std::move(z));
VERIFY(false); // Should have thrown.
}
catch (std::out_of_range&) { }
catch (...) { VERIFY(false); } // Wrong exception.
VERIFY(amapr.size() == 5);
VERIFY(z.s.size() == 3); // not moved from
}
void test_op_bracket()
{
std::map<X, Y, cmp> amap{cmp{}};
amap.insert({{Y{"abc"}, 1}, {Y{"def"}, 2}, {Y{"ghi"}, 3}});
{
Y z{"deg"};
amap[z] = 4;
VERIFY(amap.size() == 4);
VERIFY(z.s.size() == 3); // pass by value, not moved from.
amap[std::move(z)] = Y{5};
VERIFY(amap.size() == 4);
VERIFY(amap.at(z) == Y{5});
VERIFY(z.s.size() == 3); // already there, not moved from.
}
{
Y y{"deh"};
Y& v = amap[std::move(y)];
VERIFY(v == Y{});
VERIFY(amap.size() == 5);
VERIFY(amap.at(Y{"deh"}) == Y{});
VERIFY(y.s.empty()); // moved from.
}
{
Y x{"dei"};
amap[std::move(x)] = Y{7};
VERIFY(amap.size() == 6);
VERIFY(amap.at(Y{"dei"}) == Y{7});
VERIFY(x.s.empty()); // moved from
}
}
void test_try_emplace()
{
std::map<X, Y, cmp> amap{cmp{}};
amap.insert({{Y{"abc"}, 1}, {Y{"def"}, 2}, {Y{"ghi"}, 3}});
{ // Fail, already there
auto a = amap;
auto [it, res] = a.try_emplace(Y{"def"}, Y{"xyz"});
VERIFY(!res);
VERIFY(a.size() == 3);
VERIFY(a.at(Y{"def"}) == Y{2}); // unchanged
}
{ // Fail, already there, move
auto a = amap;
Y x{"def"};
Y y{"xyz"};
auto [it, res] = a.try_emplace(std::move(x), std::move(y));
VERIFY(!res);
VERIFY(a.size() == 3);
VERIFY(a.at(Y{"def"}) == Y{2}); // unchanged
VERIFY(x.s.size() == 3); // not moved from
VERIFY(y.s.size() == 3); // not moved from
}
{ // Succeed, construct
auto a = amap;
{
Y m{"m"}, n{"n"};
auto [it, res] = a.try_emplace(Y{"deg"}, m, n);
VERIFY(res);
VERIFY(a.size() == 4);
VERIFY(it->first == X{"deg"});
VERIFY(it->second == Y{"m1n"});
VERIFY(m.s.size() == 1);
VERIFY(n.s.size() == 1);
}
{
Y m{"m"}, n{"n"};
auto [it, res] = a.try_emplace(Y{"deh"}, m, std::move(n));
VERIFY(res);
VERIFY(a.size() == 5);
VERIFY(it->first == X{"deh"});
VERIFY(it->second == Y{"m2n"});
VERIFY(m.s.size() == 1);
VERIFY(n.s.empty());
}
{
Y m{"m"}, o{"o"};
auto [it, res] = a.try_emplace(Y{"dei"}, std::move(m), o);
VERIFY(res);
VERIFY(a.size() == 6);
VERIFY(it->first == X{"dei"});
VERIFY(it->second == Y{"m3o"});
VERIFY(m.s.empty());
VERIFY(o.s.size() == 1);
}
{
Y o{"o"}, p{"p"};
auto [it, res] = a.try_emplace(Y{"dej"}, std::move(o), std::move(p));
VERIFY(res);
VERIFY(a.size() == 7);
VERIFY(it->first == X{"dej"});
VERIFY(it->second == Y{"o4p"});
VERIFY(o.s.empty());
VERIFY(p.s.empty());
}
{
Y dek{"dek"};
auto [it, res] = a.try_emplace(std::move(dek), Y("q"), Y("r"));
VERIFY(res);
VERIFY(a.size() == 8);
VERIFY(dek.s.empty());
VERIFY(it->first == X{"dek"});
VERIFY(it->second == Y{"q4r"});
}
}
{ // Succeed, move
auto a = amap;
Y y{"tuv"}, z{"xyz"};
auto [it, res] = a.try_emplace(std::move(y), std::move(z));
VERIFY(res);
VERIFY(it->first == X{"tuv"});
VERIFY(it->second == Y{"xyz"});
VERIFY(a.size() == 4);
VERIFY(y.s.empty()); // moved from
VERIFY(z.s.empty()); // moved from
}
{ // Hinted, fail
auto a = amap;
Y y{"def"}, z{"xyz"};
auto it = a.try_emplace(a.begin(), std::move(y), std::move(z));
VERIFY(a.size() == 3);
VERIFY(it->first == X{"def"});
VERIFY(it->second == Y{2});
VERIFY(y.s.size() == 3); // not moved from
VERIFY(z.s.size() == 3); // not moved from
}
{ // Hinted, fail, move
auto a = amap;
Y y{"def"}, z{"xyz"};
auto it = a.try_emplace(a.begin(), std::move(y), std::move(z));
VERIFY(a.size() == 3);
VERIFY(it->first == X{"def"});
VERIFY(it->second == Y{2});
VERIFY(y.s.size() == 3); // not moved from
VERIFY(z.s.size() == 3); // not moved from
}
{ // Hinted, succeed, construct
auto a = amap;
{
Y m("m"), n("n");
auto it = a.try_emplace(a.begin(), Y{"deg"}, m, n);
VERIFY(a.size() == 4);
VERIFY(it->first == X{"deg"});
VERIFY(it->second == Y{"m1n"});
VERIFY(m.s.size() == 1);
VERIFY(n.s.size() == 1);
}
{
Y m("m"), n("n");
auto it = a.try_emplace(a.begin(), Y{"deh"}, m, std::move(n));
VERIFY(a.size() == 5);
VERIFY(it->first == X{"deh"});
VERIFY(it->second == Y{"m2n"});
VERIFY(m.s.size() == 1);
VERIFY(n.s.empty());
}
{
Y m("m"), o("o");
auto it = a.try_emplace(a.begin(), Y{"dei"}, std::move(m), o);
VERIFY(a.size() == 6);
VERIFY(it->first == X{"dei"});
VERIFY(it->second == Y{"m3o"});
VERIFY(m.s.empty());
VERIFY(o.s.size() == 1);
}
{
Y o("o"), p("p");
auto it = a.try_emplace(a.begin(), Y{"dej"}, std::move(o), std::move(p));
VERIFY(a.size() == 7);
VERIFY(it->first == X{"dej"});
VERIFY(it->second == Y{"o4p"});
VERIFY(o.s.empty());
VERIFY(p.s.empty());
}
{
Y dek("dek");
auto it = a.try_emplace(a.begin(), std::move(dek), Y("q"), Y("r"));
VERIFY(a.size() == 8);
VERIFY(dek.s.empty());
VERIFY(it->first == X{"dek"});
VERIFY(it->second == Y{"q4r"});
}
}
{ // Hinted, succeed, move
auto a = amap;
Y y{"tuv"}, z{"xyz"};
auto it = a.try_emplace(a.begin(), std::move(y), std::move(z));
VERIFY(it->first == X{"tuv"});
VERIFY(it->second == Y{"xyz"});
VERIFY(a.size() == 4);
VERIFY(y.s.empty()); // moved from
VERIFY(z.s.empty()); // moved from
}
}
void test_insert_or_assign()
{
std::map<X, Y, cmp> amap{cmp{}};
amap.insert({{Y{"abc"}, 1}, {Y{"def"}, 2}, {Y{"ghi"}, 3}});
{ // Already there, replace
auto a = amap;
Y y{"def"}, z{"xyz"};
auto [it, res] = a.insert_or_assign(y, z);
VERIFY(!res);
VERIFY(a.size() == 3);
VERIFY(a.at(Y{"def"}) == Y{"xyz"});
VERIFY(y.s.size() == 3); // not moved from
VERIFY(z.s.size() == 3); // not moved from
}
{ // Already there, move
auto a = amap;
Y y{"def"}, z{"xyz"};
auto [it, res] = a.insert_or_assign(std::move(y), std::move(z));
VERIFY(!res);
VERIFY(a.size() == 3);
VERIFY(a.at(Y{"def"}) == Y{"xyz"});
VERIFY(y.s.size() == 3); // not moved from
VERIFY(z.s.empty()); // moved from
}
{ // Succeed, move
auto a = amap;
Y y{"tuv"}, z{"xyz"};
auto [it, res] = a.insert_or_assign(std::move(y), std::move(z));
VERIFY(res);
VERIFY(it->first == X{"tuv"});
VERIFY(it->second == Y{"xyz"});
VERIFY(a.size() == 4);
VERIFY(y.s.empty()); // moved from
VERIFY(z.s.empty()); // moved from
}
{ // Hinted, already there, replace
auto a = amap;
Y y{"def"}, z{"xyz"};
auto it = a.insert_or_assign(a.begin(), y, z);
VERIFY(a.size() == 3);
VERIFY(it->first == X{"def"});
VERIFY(it->second == Y{"xyz"});
VERIFY(y.s.size() == 3); // not moved from
VERIFY(z.s.size() == 3); // not moved from
}
{ // Hinted, already there, move
auto a = amap;
Y y{"def"}, z{"xyz"};
auto it = a.insert_or_assign(a.begin(), std::move(y), std::move(z));
VERIFY(a.size() == 3);
VERIFY(it->first == X{"def"});
VERIFY(it->second == Y{"xyz"});
VERIFY(y.s.size() == 3); // not moved from
VERIFY(z.s.empty()); // moved from
}
{ // Hinted, succeed
auto a = amap;
Y y{"tuv"}, z{"xyz"};
auto it = a.insert_or_assign(a.begin(), y, z);
VERIFY(it->first == X{"tuv"});
VERIFY(it->second == Y{"xyz"});
VERIFY(a.size() == 4);
VERIFY(y.s.size() == 3); // not moved from
VERIFY(z.s.size() == 3); // not moved from
}
{ // Hinted, succeed, move
auto a = amap;
Y y{"tuv"}, z{"xyz"};
auto it = a.insert_or_assign(a.begin(), std::move(y), std::move(z));
VERIFY(it->first == X{"tuv"});
VERIFY(it->second == Y{"xyz"});
VERIFY(a.size() == 4);
VERIFY(y.s.empty()); // moved from
VERIFY(z.s.empty()); // moved from
}
}
struct Z {
std::string s;
mutable int compares = 0;
Z() = default;
Z(Z&& z) : s(std::move(z.s)) { z.s.clear(); }
Z(const Z& z) = default;
Z& operator=(Z&& z) { s = std::move(z.s); z.s.clear(); return *this; }
Z& operator=(const Z& z) = default;
Z(std::string_view sv) : s(sv) {}
Z(int n) : s(std::string(n, 'a')) {}
friend auto operator<=>(Z const& a, Z const& b) = default;
friend auto operator<=>(X const& a, Z const& b)
{ return ++b.compares, a.s.substr(0, b.s.size()) <=> b.s; }
};
X::X(Z&& z) : s(std::move(z.s)) { z.s.clear(); }
X::X(const Z& z) : s(z.s) {}
// A heterogeneous key type like Z here that compares equal
// if it matches just the first part of the key is allowed,
// which affects op[], try_emplace, and insert_or_assign.
auto populate(auto a)
{
const std::string vs[] = { "dec", "ded", "dee", "def", "deg", "deh", "dei" };
for (auto const& v : vs)
a[Y{v}] = Y{v};
return a;
}
void test_op_bracket_prefix()
{
std::map<X, Y, cmp> amap{cmp{}};
amap.insert({{Y{"abc"}, 1}, {Y{"def"}, 2}, {Y{"ghi"}, 3}});
{ // Already there, multiple matches
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"de"};
a[std::move(z)] = Y{5};
VERIFY(a.size() == 9);
VERIFY(a.at(X{"dec"}) == Y{5}); // lower_bound match changed
VERIFY(a.at(X{"ded"}) == Y{"ded"});
VERIFY(a.at(X{"dee"}) == Y{"dee"});
VERIFY(a.at(X{"def"}) == Y{"def"});
VERIFY(a.at(X{"deg"}) == Y{"deg"});
VERIFY(a.at(X{"deh"}) == Y{"deh"});
VERIFY(a.at(X{"dei"}) == Y{"dei"});
VERIFY(z.s.size() == 2); // not moved from
}
}
void test_try_emplace_prefix()
{
std::map<X, Y, cmp> amap{cmp{}};
amap.insert({{Y{"abc"}, 1}, {Y{"def"}, 2}, {Y{"ghi"}, 3}});
{
auto a = populate(amap);
VERIFY(a.size() == 9);
{
Z z{"de"};
auto [it, res] = a.try_emplace(std::move(z), 5);
VERIFY(a.size() == 9);
VERIFY(!res);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{"dec"});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // lower_bound match unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
}
{
Z z{"df"};
auto [it, res] = a.try_emplace(std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(res);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
}
{ // hinted
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"aaa"};
auto it = a.try_emplace(a.begin(), std::move(z), 5);
VERIFY(a.size() == 10);
VERIFY(it->first == X{"aaa"});
VERIFY(it->second == Y{5});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 1);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"de"};
auto it = a.try_emplace(a.find(X{"dec"}), std::move(z), 5);
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{"dec"});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
VERIFY(z.compares == 3);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.begin(), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares > 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(std::next(a.begin()), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares > 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(std::prev(a.end()), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares == 2);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.end(), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares > 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.find(X{"dei"}), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares == 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.find(X{"dec"}), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares > 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
}
{ // hinted
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"de"};
auto it = a.try_emplace(a.find(X{"dec"}), std::move(z), 5);
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{"dec"});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
VERIFY(z.compares == 3);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"de"};
auto it = a.try_emplace(a.begin(), std::move(z), 5);
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{"dec"});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
VERIFY(z.compares > 3);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"de"};
auto it = a.try_emplace(a.find(X{"dei"}), std::move(z), 5);
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{"dec"});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
VERIFY(z.compares > 3);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"de"};
auto it = a.try_emplace(a.find(X{"ghi"}), std::move(z), 5);
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{"dec"});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
VERIFY(z.compares > 3);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"de"};
auto it = a.try_emplace(a.end(), std::move(z), 5);
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{"dec"});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
VERIFY(z.compares > 3);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.begin(), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares > 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(std::next(a.begin()), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares > 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.find(X{"dei"}), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares == 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.find(X{"dec"}), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares > 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(std::prev(a.end()), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares == 2);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.end(), std::move(z), Y{6});
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{6});
VERIFY(z.s.size() == 0); // moved from
VERIFY(z.compares > 3);
auto it2 = a.find(X{"dei"});
VERIFY(it2 != a.end());
++it2;
VERIFY(it2 != a.end());
VERIFY(it2->first == X{"df"});
}
}
}
void test_insert_or_assign_prefix()
{
std::map<X, Y, cmp> amap{cmp{}};
amap.insert({{Y{"abc"}, 1}, {Y{"def"}, 2}, {Y{"ghi"}, 3}});
{ // Already there, replace
{
Z z{"de"};
auto a = populate(amap);
auto [it, res] = a.insert_or_assign(z, Y{5});
VERIFY(!res);
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{5});
VERIFY(a.at(Y{"dec"}) == Y{5}); // lower_bound changed
VERIFY(a.at(Y{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(Y{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(Y{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(Y{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(Y{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(Y{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
}
{
Z z{"de"};
auto a = populate(amap);
auto [it, res] = a.insert_or_assign(std::move(z), Y{5});
VERIFY(!res);
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{5});
VERIFY(a.at(Y{"dec"}) == Y{5}); // lower_bound changed
VERIFY(a.at(Y{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(Y{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(Y{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(Y{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(Y{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(Y{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
}
}
{ // Hinted, already there, replace
{
Z z{"de"};
auto a = populate(amap);
auto it = a.insert_or_assign(a.find(X{"dec"}), z, Y{5});
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{5});
VERIFY(a.at(Y{"dec"}) == Y{5}); // lower_bound changed
VERIFY(a.at(Y{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(Y{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(Y{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(Y{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(Y{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(Y{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
VERIFY(z.compares == 3);
}
{
Z z{"de"};
auto a = populate(amap);
auto it = a.insert_or_assign(a.end(), std::move(z), Y{5});
VERIFY(a.size() == 9);
VERIFY(it->first == X{"dec"});
VERIFY(it->second == Y{5});
VERIFY(a.at(Y{"dec"}) == Y{5}); // lower_bound changed
VERIFY(a.at(Y{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(Y{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(Y{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(Y{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(Y{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(Y{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.size() == 2); // not moved from
VERIFY(z.compares > 3);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.find(X{"dei"}), std::move(z), 5);
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{5});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 3);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"df"};
auto it = a.try_emplace(a.find(X{"ghi"}), std::move(z), 5);
VERIFY(a.size() == 10);
VERIFY(it->first == X{"df"});
VERIFY(it->second == Y{5});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 2);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"jkl"};
auto it = a.try_emplace(a.find(X{"ghi"}), std::move(z), 5);
VERIFY(a.size() == 10);
VERIFY(it->first == X{"jkl"});
VERIFY(it->second == Y{5});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 2);
}
{
auto a = populate(amap);
VERIFY(a.size() == 9);
Z z{"jkl"};
auto it = a.try_emplace(a.end(), std::move(z), 5);
VERIFY(a.size() == 10);
VERIFY(it->first == X{"jkl"});
VERIFY(it->second == Y{5});
VERIFY(a.at(X{"dec"}) == Y{"dec"}); // unchanged
VERIFY(a.at(X{"ded"}) == Y{"ded"}); // unchanged
VERIFY(a.at(X{"dee"}) == Y{"dee"}); // unchanged
VERIFY(a.at(X{"def"}) == Y{"def"}); // unchanged
VERIFY(a.at(X{"deg"}) == Y{"deg"}); // unchanged
VERIFY(a.at(X{"deh"}) == Y{"deh"}); // unchanged
VERIFY(a.at(X{"dei"}) == Y{"dei"}); // unchanged
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 1);
}
}
}
int main()
{
test_at();
test_op_bracket();
test_try_emplace();
test_insert_or_assign();
test_op_bracket_prefix();
test_try_emplace_prefix();
test_insert_or_assign_prefix();
}