brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · 7fb0c0e Raw
203 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(flat_multiset&&);14 15#include <algorithm>16#include <deque>17#include <flat_set>18#include <functional>19#include <utility>20#include <vector>21 22#include "../helpers.h"23#include "test_macros.h"24#include "../../../test_compare.h"25#include "test_allocator.h"26#include "min_allocator.h"27 28template <template <class...> class KeyContainer>29constexpr void test() {30  {31    using C = test_less<int>;32    using A = test_allocator<int>;33    using M = std::flat_multiset<int, C, KeyContainer<int, A>>;34    M mo    = M({1, 2, 1, 3}, C(5), A(7));35    M m     = std::move(mo);36    assert((m == M{1, 1, 2, 3}));37    assert(m.key_comp() == C(5));38    assert(std::move(m).extract().get_allocator() == A(7));39 40    assert(mo.empty());41    assert(mo.key_comp() == C(5));42    assert(std::move(mo).extract().get_allocator().get_id() == test_alloc_base::moved_value);43  }44  {45    using C = test_less<int>;46    using A = min_allocator<int>;47    using M = std::flat_multiset<int, C, KeyContainer<int, A>>;48    M mo    = M({1, 2, 1, 3}, C(5), A());49    M m     = std::move(mo);50    assert((m == M{1, 1, 2, 3}));51    assert(m.key_comp() == C(5));52    assert(std::move(m).extract().get_allocator() == A());53 54    assert(mo.empty());55    assert(mo.key_comp() == C(5));56    assert(std::move(mo).extract().get_allocator() == A());57  }58  if (!TEST_IS_CONSTANT_EVALUATED) {59    // A moved-from flat_multiset maintains its class invariant in the presence of moved-from comparators.60    using M = std::flat_multiset<int, std::function<bool(int, int)>, KeyContainer<int>>;61    M mo    = M({1, 2, 1, 3}, std::less<int>());62    M m     = std::move(mo);63    assert(m.size() == 4);64    assert(std::is_sorted(m.begin(), m.end(), m.value_comp()));65    assert(m.key_comp()(1, 2) == true);66 67    assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp()));68    LIBCPP_ASSERT(m.key_comp()(1, 2) == true);69    LIBCPP_ASSERT(mo.empty());70    mo.insert({1, 1, 2, 3}); // insert has no preconditions71    assert(m == mo);72  }73  {74    // moved-from object maintains invariant if the underlying container does not clear after move75    using M = std::flat_multiset<int, std::less<>, CopyOnlyVector<int>>;76    M m1    = M({1, 2, 1, 3});77    M m2    = std::move(m1);78    assert(m2.size() == 4);79    check_invariant(m1);80    LIBCPP_ASSERT(m1.empty());81    LIBCPP_ASSERT(m1.size() == 0);82  }83}84 85constexpr bool test() {86  test<std::vector>();87#ifndef __cpp_lib_constexpr_deque88  if (!TEST_IS_CONSTANT_EVALUATED)89#endif90    test<std::deque>();91 92  return true;93}94 95template <class T>96struct ThrowingMoveAllocator {97  using value_type                                    = T;98  explicit ThrowingMoveAllocator()                    = default;99  ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default;100  ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {}101  T* allocate(std::ptrdiff_t n) { return std::allocator<T>().allocate(n); }102  void deallocate(T* p, std::ptrdiff_t n) { return std::allocator<T>().deallocate(p, n); }103  friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default;104};105 106struct ThrowingMoveComp {107  ThrowingMoveComp() = default;108  ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {}109  ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {}110  bool operator()(const auto&, const auto&) const { return false; }111};112 113struct MoveSensitiveComp {114  MoveSensitiveComp() noexcept(false)                  = default;115  MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default;116  MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; }117  MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default;118  MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) {119    rhs.is_moved_from_ = true;120    return *this;121  }122  bool operator()(const auto&, const auto&) const { return false; }123  bool is_moved_from_ = false;124};125 126void test_move_noexcept() {127  {128    using C = std::flat_multiset<int>;129    LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v<C>);130    C c;131    C d = std::move(c);132  }133  {134    using C = std::flat_multiset<int, std::less<int>, std::deque<int, test_allocator<int>>>;135    LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v<C>);136    C c;137    C d = std::move(c);138  }139#if _LIBCPP_VERSION140  {141    // Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators142    using C = std::flat_multiset<int, std::less<int>, std::deque<int, ThrowingMoveAllocator<int>>>;143    static_assert(!std::is_nothrow_move_constructible_v<std::deque<int, ThrowingMoveAllocator<int>>>);144    static_assert(!std::is_nothrow_move_constructible_v<C>);145    C c;146    C d = std::move(c);147  }148#endif // _LIBCPP_VERSION149  {150    // Comparator fails to be nothrow-move-constructible151    using C = std::flat_multiset<int, ThrowingMoveComp>;152    static_assert(!std::is_nothrow_move_constructible_v<C>);153    C c;154    C d = std::move(c);155  }156}157 158#if !defined(TEST_HAS_NO_EXCEPTIONS)159static int countdown = 0;160 161struct EvilContainer : std::vector<int> {162  EvilContainer() = default;163  EvilContainer(EvilContainer&& rhs) {164    // Throw on move-construction.165    if (--countdown == 0) {166      rhs.insert(rhs.end(), 0);167      rhs.insert(rhs.end(), 0);168      throw 42;169    }170  }171};172 173void test_move_exception() {174  {175    using M   = std::flat_multiset<int, std::less<int>, EvilContainer>;176    M mo      = {1, 2, 3};177    countdown = 1;178    try {179      M m = std::move(mo);180      assert(false); // not reached181    } catch (int x) {182      assert(x == 42);183    }184    // The source flat_multiset maintains its class invariant.185    check_invariant(mo);186    LIBCPP_ASSERT(mo.empty());187  }188}189#endif // !defined(TEST_HAS_NO_EXCEPTIONS)190 191int main(int, char**) {192  test();193#if TEST_STD_VER >= 26194  static_assert(test());195#endif196  test_move_noexcept();197#if !defined(TEST_HAS_NO_EXCEPTIONS)198  test_move_exception();199#endif // !defined(TEST_HAS_NO_EXCEPTIONS)200 201  return 0;202}203