brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.4 KiB · 1c3affe Raw
261 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_set>12 13// flat_set& operator=(flat_set&&);14 15#include <algorithm>16#include <deque>17#include <flat_set>18#include <functional>19#include <string>20#include <utility>21#include <vector>22 23#include "test_macros.h"24#include "MoveOnly.h"25#include "../helpers.h"26#include "../../../test_compare.h"27#include "test_allocator.h"28#include "min_allocator.h"29 30struct MoveNegates {31  int value_    = 0;32  MoveNegates() = default;33  constexpr MoveNegates(int v) : value_(v) {}34  constexpr MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; }35  constexpr MoveNegates& operator=(MoveNegates&& rhs) {36    value_     = rhs.value_;37    rhs.value_ = -rhs.value_;38    return *this;39  }40  ~MoveNegates()                             = default;41  auto operator<=>(const MoveNegates&) const = default;42};43 44struct MoveClears {45  int value_   = 0;46  MoveClears() = default;47  constexpr MoveClears(int v) : value_(v) {}48  constexpr MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; }49  constexpr MoveClears& operator=(MoveClears&& rhs) {50    value_     = rhs.value_;51    rhs.value_ = 0;52    return *this;53  }54  ~MoveClears()                             = default;55  auto operator<=>(const MoveClears&) const = default;56};57 58#if !defined(TEST_HAS_NO_EXCEPTIONS)59struct MoveAssignThrows : std::vector<int> {60  using std::vector<int>::vector;61  MoveAssignThrows& operator=(MoveAssignThrows&& other) {62    push_back(0);63    push_back(0);64    other.push_back(0);65    other.push_back(0);66    throw 42;67  }68};69#endif // TEST_HAS_NO_EXCEPTIONS70 71template <template <class...> class KeyContainer>72constexpr void test_move_assign_clears() {73  // Preserves the class invariant for the moved-from flat_set.74  {75    const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8};76    using M              = std::flat_set<MoveNegates, std::less<MoveNegates>, KeyContainer<MoveNegates>>;77    M m                  = M(expected, expected + 8);78    M m2                 = M(expected, expected + 3);79 80    m2 = std::move(m);81 82    assert(std::equal(m2.begin(), m2.end(), expected, expected + 8));83    LIBCPP_ASSERT(m.empty());84    assert(std::is_sorted(m.begin(), m.end(), m.key_comp()));                // still sorted85    assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates86    m.insert(1);87    m.insert(2);88    assert(m.contains(1));89    assert(m.find(2) != m.end());90  }91  {92    const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8};93    using M              = std::flat_set<MoveClears, std::less<MoveClears>, KeyContainer<MoveClears>>;94    M m                  = M(expected, expected + 8);95    M m2                 = M(expected, expected + 3);96 97    m2 = std::move(m);98 99    assert(std::equal(m2.begin(), m2.end(), expected, expected + 8));100    LIBCPP_ASSERT(m.empty());101    assert(std::is_sorted(m.begin(), m.end(), m.key_comp()));                // still sorted102    assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates103    m.insert(1);104    m.insert(2);105    assert(m.contains(1));106    assert(m.find(2) != m.end());107  }108  {109    // moved-from object maintains invariant if one of underlying container does not clear after move110    using M = std::flat_set<int, std::less<>, CopyOnlyVector<int>>;111    M m1    = M({1, 2, 3});112    M m2    = M({1, 2});113    m2      = std::move(m1);114    assert(m2.size() == 3);115    check_invariant(m1);116    LIBCPP_ASSERT(m1.empty());117  }118#if !defined(TEST_HAS_NO_EXCEPTIONS)119  if (!TEST_IS_CONSTANT_EVALUATED) {120    using M = std::flat_set<int, std::less<>, MoveAssignThrows>;121    M m1    = {1, 2, 3};122    M m2    = {1, 2};123    try {124      m2 = std::move(m1);125      assert(false);126    } catch (int e) {127      assert(e == 42);128    }129    check_invariant(m1);130    check_invariant(m2);131    LIBCPP_ASSERT(m1.empty());132    LIBCPP_ASSERT(m2.empty());133  }134#endif // TEST_HAS_NO_EXCEPTIONS135}136 137struct MoveSensitiveComp {138  MoveSensitiveComp() noexcept(false)                         = default;139  MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default;140  MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; }141  MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default;142  MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) {143    rhs.is_moved_from_ = true;144    return *this;145  }146  bool operator()(const auto&, const auto&) const { return false; }147  bool is_moved_from_ = false;148};149 150struct MoveThrowsComp {151  MoveThrowsComp(MoveThrowsComp&&) noexcept(false);152  MoveThrowsComp(const MoveThrowsComp&) noexcept(true);153  MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false);154  MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true);155  bool operator()(const auto&, const auto&) const;156};157 158void test_move_assign_no_except() {159  // This tests a conforming extension160 161  {162    using C = std::flat_set<int, int>;163    LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);164  }165  {166    using C = std::flat_set<MoveOnly, std::less<MoveOnly>, std::vector<MoveOnly, test_allocator<MoveOnly>>>;167    static_assert(!std::is_nothrow_move_assignable_v<C>);168  }169  {170    using C = std::flat_set<int, std::less<int>, std::vector<int, test_allocator<int>>>;171    static_assert(!std::is_nothrow_move_assignable_v<C>);172  }173  {174    using C = std::flat_set<MoveOnly, std::less<MoveOnly>, std::vector<MoveOnly, other_allocator<MoveOnly>>>;175    LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);176  }177  {178    using C = std::flat_set<int, std::less<int>, std::vector<int, other_allocator<int>>>;179    LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);180  }181  {182    // Test with a comparator that throws on move-assignment.183    using C = std::flat_set<int, MoveThrowsComp>;184    LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v<C>);185  }186  {187    // Test with a container that throws on move-assignment.188    using C = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;189    static_assert(!std::is_nothrow_move_assignable_v<C>);190  }191}192 193template <template <class...> class KeyContainer>194constexpr void test() {195  {196    using C                           = test_less<int>;197    using A1                          = test_allocator<int>;198    using M                           = std::flat_set<int, C, KeyContainer<int, A1>>;199    M mo                              = M({1, 2, 3}, C(5), A1(7));200    M m                               = M({}, C(3), A1(7));201    std::same_as<M&> decltype(auto) r = m = std::move(mo);202    assert(&r == &m);203    assert((m == M{1, 2, 3}));204    assert(m.key_comp() == C(5));205    auto ks = std::move(m).extract();206    assert(ks.get_allocator() == A1(7));207    assert(mo.empty());208  }209  {210    using C                           = test_less<int>;211    using A1                          = other_allocator<int>;212    using M                           = std::flat_set<int, C, KeyContainer<int, A1>>;213    M mo                              = M({4, 5}, C(5), A1(7));214    M m                               = M({1, 2, 3, 4}, C(3), A1(7));215    std::same_as<M&> decltype(auto) r = m = std::move(mo);216    assert(&r == &m);217    assert((m == M{4, 5}));218    assert(m.key_comp() == C(5));219    auto ks = std::move(m).extract();220    assert(ks.get_allocator() == A1(7));221    assert(mo.empty());222  }223  {224    using A                           = min_allocator<int>;225    using M                           = std::flat_set<int, std::greater<int>, KeyContainer<int, A>>;226    M mo                              = M({5, 4, 3}, A());227    M m                               = M({4, 3, 2, 1}, A());228    std::same_as<M&> decltype(auto) r = m = std::move(mo);229    assert(&r == &m);230    assert((m == M{5, 4, 3}));231    auto ks = std::move(m).extract();232    assert(ks.get_allocator() == A());233    assert(mo.empty());234  }235}236 237constexpr bool test() {238  test<std::vector>();239  test_move_assign_clears<std::vector>();240 241#ifndef __cpp_lib_constexpr_deque242  if (!TEST_IS_CONSTANT_EVALUATED)243#endif244  {245    test<std::deque>();246    test_move_assign_clears<std::deque>();247  }248 249  return true;250}251 252int main(int, char**) {253  test();254  test_move_assign_no_except();255#if TEST_STD_VER >= 26256  static_assert(test());257#endif258 259  return 0;260}261