brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 0d04d26 Raw
148 lines · c
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#ifndef SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H10#define SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H11 12#include <algorithm>13#include <array>14#include <cassert>15#include <cstddef>16#include <iterator>17#include <ranges>18#include <utility>19 20#include "../exception_safety_helpers.h"21#include "../from_range_helpers.h"22#include "MoveOnly.h"23#include "almost_satisfies_types.h"24#include "count_new.h"25#include "test_iterators.h"26#include "test_macros.h"27 28template <class T>29concept HasSize = requires(const T& value) { value.size(); };30 31template <class Container, class Range>32concept HasFromRangeCtr = requires(Range&& range) {33  Container(std::from_range, std::forward<Range>(range));34  Container(std::from_range, std::forward<Range>(range), std::allocator<typename Container::value_type>());35};36 37template <template <class...> class Container, class T, class U>38constexpr bool test_constraints() {39  // Input range with the same value type.40  static_assert(HasFromRangeCtr<Container<T>, InputRange<T>>);41  // Input range with a convertible value type.42  static_assert(HasFromRangeCtr<Container<T>, InputRange<U>>);43  // Input range with a non-convertible value type.44  static_assert(!HasFromRangeCtr<Container<T>, InputRange<Empty>>);45  // Not an input range.46  static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotDerivedFrom>);47  static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotIndirectlyReadable>);48  static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotInputOrOutputIterator>);49 50  // Note: there are no constraints on the allocator (it's not a separate template type of the constructor)`.51 52  return true;53}54 55// Note: `std::array` is used to avoid dealing with `vector<bool>`.56template <template <class...> class Container,57          class T,58          class Iter,59          class Sent,60          class Alloc,61          std::size_t N,62          class ValidateFunc>63constexpr void test_sequence_container_with_input(std::array<T, N>&& input, ValidateFunc validate) {64  { // (range)65    auto in = wrap_input<Iter, Sent>(input);66    Container<T> c(std::from_range, in);67 68    if constexpr (HasSize<Container<T>>) {69      assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));70    }71    assert(std::ranges::equal(input, c));72    validate(c);73  }74 75  { // (range, allocator)76    auto in = wrap_input<Iter, Sent>(input);77    Alloc alloc;78    Container<T, Alloc> c(std::from_range, in, alloc);79 80    assert(c.get_allocator() == alloc);81    if constexpr (HasSize<Container<T, Alloc>>) {82      assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));83    }84    assert(std::ranges::equal(input, c));85    validate(c);86  }87}88 89template <template <class...> class Container, class T, class Iter, class Sent, class Alloc, class ValidateFunc>90constexpr void test_sequence_container(ValidateFunc validate) {91  // Normal input.92  test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array{0, 5, 12, 7, -1, 8, 26}, validate);93  // Empty input.94  test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array<int, 0>{}, validate);95  // Single-element input.96  test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array{5}, validate);97}98 99template <template <class...> class Container>100constexpr void test_sequence_container_move_only() {101  MoveOnly input[5];102  std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});103 104  [[maybe_unused]] Container<MoveOnly> c(std::from_range, in);105}106 107template <class Iter, class Sent, class Alloc, class ValidateFunc>108constexpr void test_vector_bool(ValidateFunc validate) {109  // Normal input.110  test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(111      std::array{true, false, false, true, false, true, true, true, false, true}, validate);112  // Empty input.113  test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(std::array<bool, 0>{}, validate);114  // Single-element input.115  test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(std::array{true}, validate);116}117 118template <template <class...> class Container>119void test_exception_safety_throwing_copy() {120#if !defined(TEST_HAS_NO_EXCEPTIONS)121  constexpr int ThrowOn = 3;122  using T               = ThrowingCopy<ThrowOn>;123  test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {124    [[maybe_unused]] Container<T> c(std::from_range, std::ranges::subrange(from, to));125  });126#endif127}128 129template <template <class...> class Container, class T>130void test_exception_safety_throwing_allocator() {131#if !defined(TEST_HAS_NO_EXCEPTIONS)132  T in[] = {0, 1};133 134  try {135    ThrowingAllocator<T> alloc;136 137    globalMemCounter.reset();138    Container<T, ThrowingAllocator<T>> c(std::from_range, in, alloc);139    assert(false); // The constructor call above should throw.140 141  } catch (int) {142    assert(globalMemCounter.new_called == globalMemCounter.delete_called);143  }144#endif145}146 147#endif // SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H148