brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.9 KiB · 62e2181 Raw
254 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_multiset& operator=(flat_multiset&&);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  MoveNegates(int v) : value_(v) {}34  MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; }35  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  MoveClears(int v) : value_(v) {}48  MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; }49  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 71void test_move_assign_clears() {72  // Preserves the class invariant for the moved-from flat_multiset.73  {74    const int expected[] = {1, 1, 2, 3, 4, 5, 6, 7, 8};75    using M              = std::flat_multiset<MoveNegates, std::less<MoveNegates>>;76    M m                  = M(expected, expected + 9);77    M m2                 = M(expected, expected + 4);78 79    m2 = std::move(m);80 81    assert(std::equal(m2.begin(), m2.end(), expected, expected + 9));82    LIBCPP_ASSERT(m.empty());83    check_invariant(m);84    m.insert(1);85    m.insert(2);86    assert(m.contains(1));87    assert(m.find(2) != m.end());88  }89  {90    const int expected[] = {1, 1, 2, 3, 4, 5, 6, 7, 8};91    using M              = std::flat_multiset<MoveClears, std::less<MoveClears>>;92    M m                  = M(expected, expected + 9);93    M m2                 = M(expected, expected + 4);94 95    m2 = std::move(m);96 97    assert(std::equal(m2.begin(), m2.end(), expected, expected + 9));98    LIBCPP_ASSERT(m.empty());99    check_invariant(m);100    m.insert(1);101    m.insert(2);102    assert(m.contains(1));103    assert(m.find(2) != m.end());104  }105  {106    // moved-from object maintains invariant if the underlying container does not clear after move107    using M = std::flat_multiset<int, std::less<>, CopyOnlyVector<int>>;108    M m1    = M({1, 1, 2, 3});109    M m2    = M({1, 2});110    m2      = std::move(m1);111    assert(m2.size() == 4);112    check_invariant(m1);113    LIBCPP_ASSERT(m1.empty());114  }115#if !defined(TEST_HAS_NO_EXCEPTIONS)116  {117    using M = std::flat_multiset<int, std::less<>, MoveAssignThrows>;118    M m1    = {1, 1, 2, 3};119    M m2    = {1, 1, 2};120    try {121      m2 = std::move(m1);122      assert(false);123    } catch (int e) {124      assert(e == 42);125    }126    check_invariant(m1);127    check_invariant(m2);128    LIBCPP_ASSERT(m1.empty());129    LIBCPP_ASSERT(m2.empty());130  }131#endif // TEST_HAS_NO_EXCEPTIONS132}133 134struct MoveSensitiveComp {135  MoveSensitiveComp() noexcept(false)                         = default;136  MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default;137  MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; }138  MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default;139  MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) {140    rhs.is_moved_from_ = true;141    return *this;142  }143  bool operator()(const auto&, const auto&) const { return false; }144  bool is_moved_from_ = false;145};146 147struct MoveThrowsComp {148  MoveThrowsComp(MoveThrowsComp&&) noexcept(false);149  MoveThrowsComp(const MoveThrowsComp&) noexcept(true);150  MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false);151  MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true);152  bool operator()(const auto&, const auto&) const;153};154 155void test_move_assign_no_except() {156  // This tests a conforming extension157 158  {159    using C = std::flat_multiset<int, int>;160    LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);161  }162  {163    using C = std::flat_multiset<MoveOnly, std::less<MoveOnly>, std::vector<MoveOnly, test_allocator<MoveOnly>>>;164    static_assert(!std::is_nothrow_move_assignable_v<C>);165  }166  {167    using C = std::flat_multiset<int, std::less<int>, std::vector<int, test_allocator<int>>>;168    static_assert(!std::is_nothrow_move_assignable_v<C>);169  }170  {171    using C = std::flat_multiset<MoveOnly, std::less<MoveOnly>, std::vector<MoveOnly, other_allocator<MoveOnly>>>;172    LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);173  }174  {175    using C = std::flat_multiset<int, std::less<int>, std::vector<int, other_allocator<int>>>;176    LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);177  }178  {179    // Test with a comparator that throws on move-assignment.180    using C = std::flat_multiset<int, MoveThrowsComp>;181    LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v<C>);182  }183  {184    // Test with a container that throws on move-assignment.185    using C = std::flat_multiset<int, std::less<int>, std::pmr::vector<int>>;186    static_assert(!std::is_nothrow_move_assignable_v<C>);187  }188}189 190template <template <class...> class KeyContainer>191constexpr void test() {192  {193    using C                           = test_less<int>;194    using A1                          = other_allocator<int>;195    using M                           = std::flat_multiset<int, C, KeyContainer<int, A1>>;196    M mo                              = M({4, 4, 5}, C(5), A1(7));197    M m                               = M({1, 1, 2, 3, 4}, C(3), A1(7));198    std::same_as<M&> decltype(auto) r = m = std::move(mo);199    assert(&r == &m);200    assert((m == M{4, 4, 5}));201    assert(m.key_comp() == C(5));202    auto ks = std::move(m).extract();203    assert(ks.get_allocator() == A1(7));204    assert(mo.empty());205  }206  {207    using A                           = min_allocator<int>;208    using M                           = std::flat_multiset<int, std::greater<int>, KeyContainer<int, A>>;209    M mo                              = M({5, 3, 4, 3}, A());210    M m                               = M({4, 1, 3, 2, 1}, A());211    std::same_as<M&> decltype(auto) r = m = std::move(mo);212    assert(&r == &m);213    assert((m == M{5, 4, 3, 3}));214    auto ks = std::move(m).extract();215    assert(ks.get_allocator() == A());216    assert(mo.empty());217  }218  {219    using C                           = test_less<int>;220    using A1                          = test_allocator<int>;221    using M                           = std::flat_multiset<int, C, KeyContainer<int, A1>>;222    M mo                              = M({1, 1, 2, 3}, C(5), A1(7));223    M m                               = M({}, C(3), A1(7));224    std::same_as<M&> decltype(auto) r = m = std::move(mo);225    assert(&r == &m);226    assert((m == M{1, 1, 2, 3}));227    assert(m.key_comp() == C(5));228    auto ks = std::move(m).extract();229    assert(ks.get_allocator() == A1(7));230    assert(mo.empty());231  }232}233 234constexpr bool test() {235  test<std::vector>();236#ifndef __cpp_lib_constexpr_deque237  if (!TEST_IS_CONSTANT_EVALUATED)238#endif239    test<std::deque>();240 241  return true;242}243 244int main(int, char**) {245  test();246#if TEST_STD_VER >= 26247  static_assert(test());248#endif249  test_move_assign_clears();250  test_move_assign_no_except();251 252  return 0;253}254