blob: 5733e66fb2bd71e51369e6345420b16d1889b5a7 [file]
// { dg-do run { target c++26 } }
#include <set>
#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&& y);
X(const Y& y);
X(Z&& z);
X(const Z& z);
friend auto operator<=>(X const& a, X const& b) = default;
};
struct Y {
std::string s;
Y() = default;
Y(std::string_view sv) : s(sv) {}
Y(int a, int b = 0) : s(std::string('a', a + b)) {}
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;
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_root()
{
std::set<X, cmp> aset{cmp{}};
aset.insert(Y{"def"});
VERIFY(aset.size() == 1);
VERIFY(aset.contains(X{"def"}));
aset.insert(Y{"abc"});
VERIFY(aset.size() == 2);
VERIFY(aset.contains(X{"abc"}));
aset.insert(Y{"ghi"});
VERIFY(aset.size() == 3);
VERIFY(aset.contains(X{"ghi"}));
}
void test_insert()
{
std::set<X, cmp> aset{cmp{}};
aset.insert({Y{"abc"}, Y{"def"}, Y{"ghi"}});
{ // Fail
auto a = aset;
Y y{"def"};
auto [it, res] = a.insert(y);
VERIFY(!res);
VERIFY(a.size() == 3);
VERIFY(it->s == "def");
VERIFY(y.s.size() == 3); // not moved
}
{ // Fail, move
auto a = aset;
Y y{"def"};
auto [it, res] = a.insert(std::move(y));
VERIFY(!res);
VERIFY(a.size() == 3);
VERIFY(it->s == "def");
VERIFY(y.s.size() == 3); // not moved
}
{ // Succeed
auto a = aset;
Y y{"deg"};
auto [it, res] = a.insert(y);
VERIFY(res);
VERIFY(a.size() == 4);
VERIFY(it->s == "deg");
VERIFY(y.s.size() == 3); // not moved
}
{ // Succeed, move
auto a = aset;
Y y{"deg"};
auto [it, res] = a.insert(std::move(y));
VERIFY(res);
VERIFY(a.size() == 4);
VERIFY(it->s == "deg");
VERIFY(y.s.empty()); // moved
}
{ // Hinted, fail
auto a = aset;
Y y{"def"};
auto it = a.insert(a.begin(), y);
VERIFY(a.size() == 3);
VERIFY(it->s == "def");
VERIFY(y.s.size() == 3); // not moved
}
{ // Hinted, fail, move
auto a = aset;
Y y{"def"};
auto it = a.insert(a.begin(), std::move(y));
VERIFY(a.size() == 3);
VERIFY(it->s == "def");
VERIFY(y.s.size() == 3); // not moved
}
{ // Hinted, succeed
auto a = aset;
Y y{"deh"};
auto it = a.insert(a.begin(), y);
VERIFY(a.size() == 4);
VERIFY(it->s == "deh");
VERIFY(y.s.size() == 3); // not moved
}
{ // Hinted, succeed, move
auto a = aset;
Y y{"deh"};
auto it = a.insert(a.begin(), std::move(y));
VERIFY(a.size() == 4);
VERIFY(it->s == "deh");
VERIFY(y.s.empty()); // moved
}
}
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.insert(Y{v});
return a;
}
void test_insert_prefix()
{
std::set<X, cmp> aset{cmp{}};
aset.insert({Y{"abc"}, Y{"def"}, Y{"ghi"}});
{
{ // Already there, fail.
Z z{"de"};
auto a = populate(aset);
auto [it, res] = a.insert(std::move(z));
VERIFY(!res);
VERIFY(a.size() == 9);
VERIFY(*it == X{"dec"});
VERIFY(!a.contains(Y{"de"}));
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.size() == 2); // not moved from
VERIFY(z.compares > 3);
}
}
{
{ // hinted, succeed
Z z{"aaa"};
auto a = populate(aset);
auto it = a.insert(a.begin(), std::move(z));
VERIFY(a.size() == 10);
VERIFY(*it == X{"aaa"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 1);
}
}
{ // Hinted, already there, fail.
{
Z z{"de"};
auto a = populate(aset);
auto it = a.insert(a.begin(), std::move(z));
VERIFY(a.size() == 9);
VERIFY(*it == X{"dec"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.size() == 2);
VERIFY(z.compares > 3);
}
{
Z z{"de"};
auto a = populate(aset);
auto it = a.insert(a.find(X{"dec"}), std::move(z));
VERIFY(a.size() == 9);
VERIFY(*it == X{"dec"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.size() == 2);
VERIFY(z.compares == 3);
}
{
Z z{"de"};
auto a = populate(aset);
auto it = a.insert(a.find(X{"def"}), std::move(z));
VERIFY(a.size() == 9);
VERIFY(*it == X{"dec"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.size() == 2);
VERIFY(z.compares > 3);
}
{
Z z{"de"};
auto a = populate(aset);
auto it = a.insert(a.find(X{"dei"}), std::move(z));
VERIFY(a.size() == 9);
VERIFY(*it == X{"dec"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.size() == 2);
VERIFY(z.compares > 3);
}
{
Z z{"df"};
auto a = populate(aset);
auto it = a.insert(a.find(X{"dei"}), std::move(z));
VERIFY(a.size() == 10);
VERIFY(*it == X{"df"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 3);
}
{
Z z{"de"};
auto a = populate(aset);
auto it = a.insert(a.find(X{"ghi"}), std::move(z));
VERIFY(a.size() == 9);
VERIFY(*it == X{"dec"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.size() == 2);
VERIFY(z.compares > 3);
}
{
Z z{"df"};
auto a = populate(aset);
auto it = a.insert(a.find(X{"ghi"}), std::move(z));
VERIFY(a.size() == 10);
VERIFY(*it == X{"df"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 2);
}
{
Z z{"de"};
auto a = populate(aset);
auto it = a.insert(a.end(), std::move(z));
VERIFY(a.size() == 9);
VERIFY(*it == X{"dec"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.size() == 2);
VERIFY(z.compares > 3);
}
{
Z z{"jkl"};
auto a = populate(aset);
auto it = a.insert(a.find(X{"ghi"}), std::move(z));
VERIFY(a.size() == 10);
VERIFY(*it == X{"jkl"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 2);
}
{
Z z{"jkl"};
auto a = populate(aset);
auto it = a.insert(a.end(), std::move(z));
VERIFY(a.size() == 10);
VERIFY(*it == X{"jkl"});
VERIFY(a.contains(Y{"dec"}));
VERIFY(a.contains(Y{"ded"}));
VERIFY(a.contains(Y{"dee"}));
VERIFY(a.contains(Y{"def"}));
VERIFY(a.contains(Y{"deg"}));
VERIFY(a.contains(Y{"deh"}));
VERIFY(a.contains(Y{"dei"}));
VERIFY(z.s.empty()); // moved from
VERIFY(z.compares == 1);
}
}
}
int main()
{
test_root();
test_insert();
test_insert_prefix();
}