117bbb224Svarconst //===----------------------------------------------------------------------===// 217bbb224Svarconst // 317bbb224Svarconst // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 417bbb224Svarconst // See https://llvm.org/LICENSE.txt for license information. 517bbb224Svarconst // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 617bbb224Svarconst // 717bbb224Svarconst //===----------------------------------------------------------------------===// 817bbb224Svarconst 917bbb224Svarconst #ifndef SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H 1017bbb224Svarconst #define SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H 1117bbb224Svarconst 1217bbb224Svarconst #include <algorithm> 1317bbb224Svarconst #include <array> 1417bbb224Svarconst #include <cassert> 1517bbb224Svarconst #include <cstddef> 1617bbb224Svarconst #include <iterator> 1717bbb224Svarconst #include <ranges> 1817bbb224Svarconst #include <utility> 1917bbb224Svarconst 20d0b51657Svarconst #include "../exception_safety_helpers.h" 2117bbb224Svarconst #include "../from_range_helpers.h" 2217bbb224Svarconst #include "MoveOnly.h" 2317bbb224Svarconst #include "almost_satisfies_types.h" 2417bbb224Svarconst #include "count_new.h" 2517bbb224Svarconst #include "test_iterators.h" 2617bbb224Svarconst #include "test_macros.h" 2717bbb224Svarconst 2817bbb224Svarconst template <class T> 2917bbb224Svarconst concept HasSize = requires (const T& value) { value.size(); }; 3017bbb224Svarconst 3117bbb224Svarconst template <class Container, class Range> 3217bbb224Svarconst concept HasFromRangeCtr = requires (Range&& range) { 3317bbb224Svarconst Container(std::from_range, std::forward<Range>(range)); 3417bbb224Svarconst Container(std::from_range, std::forward<Range>(range), std::allocator<typename Container::value_type>()); 3517bbb224Svarconst }; 3617bbb224Svarconst 3717bbb224Svarconst template <template <class...> class Container, class T, class U> 3817bbb224Svarconst constexpr bool test_constraints() { 3917bbb224Svarconst // Input range with the same value type. 4017bbb224Svarconst static_assert(HasFromRangeCtr<Container<T>, InputRange<T>>); 4117bbb224Svarconst // Input range with a convertible value type. 4217bbb224Svarconst static_assert(HasFromRangeCtr<Container<T>, InputRange<U>>); 4317bbb224Svarconst // Input range with a non-convertible value type. 4417bbb224Svarconst static_assert(!HasFromRangeCtr<Container<T>, InputRange<Empty>>); 4517bbb224Svarconst // Not an input range. 4617bbb224Svarconst static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotDerivedFrom>); 4717bbb224Svarconst static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotIndirectlyReadable>); 4817bbb224Svarconst static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotInputOrOutputIterator>); 4917bbb224Svarconst 5017bbb224Svarconst // Note: there are no constraints on the allocator (it's not a separate template type of the constructor)`. 5117bbb224Svarconst 5217bbb224Svarconst return true; 5317bbb224Svarconst } 5417bbb224Svarconst 5517bbb224Svarconst // Note: `std::array` is used to avoid dealing with `vector<bool>`. 5617bbb224Svarconst template <template <class ...> class Container, 5717bbb224Svarconst class T, 5817bbb224Svarconst class Iter, 5917bbb224Svarconst class Sent, 6017bbb224Svarconst class Alloc, 6117bbb224Svarconst std::size_t N, 6217bbb224Svarconst class ValidateFunc> 6317bbb224Svarconst constexpr void test_sequence_container_with_input(std::array<T, N>&& input, ValidateFunc validate) { 6417bbb224Svarconst { // (range) 65*f73050e7SLouis Dionne auto in = wrap_input<Iter, Sent>(input); 6617bbb224Svarconst Container<T> c(std::from_range, in); 6717bbb224Svarconst 6817bbb224Svarconst if constexpr (HasSize<Container<T>>) { 6917bbb224Svarconst assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end()))); 7017bbb224Svarconst } 71*f73050e7SLouis Dionne assert(std::ranges::equal(input, c)); 7217bbb224Svarconst validate(c); 7317bbb224Svarconst } 7417bbb224Svarconst 7517bbb224Svarconst { // (range, allocator) 76*f73050e7SLouis Dionne auto in = wrap_input<Iter, Sent>(input); 7717bbb224Svarconst Alloc alloc; 7817bbb224Svarconst Container<T, Alloc> c(std::from_range, in, alloc); 7917bbb224Svarconst 8017bbb224Svarconst assert(c.get_allocator() == alloc); 8117bbb224Svarconst if constexpr (HasSize<Container<T, Alloc>>) { 8217bbb224Svarconst assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end()))); 8317bbb224Svarconst } 84*f73050e7SLouis Dionne assert(std::ranges::equal(input, c)); 8517bbb224Svarconst validate(c); 8617bbb224Svarconst } 8717bbb224Svarconst } 8817bbb224Svarconst 8917bbb224Svarconst template <template <class ...> class Container, 9017bbb224Svarconst class T, 9117bbb224Svarconst class Iter, 9217bbb224Svarconst class Sent, 9317bbb224Svarconst class Alloc, 9417bbb224Svarconst class ValidateFunc> 9517bbb224Svarconst constexpr void test_sequence_container(ValidateFunc validate) { 9617bbb224Svarconst // Normal input. 9717bbb224Svarconst test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array{0, 5, 12, 7, -1, 8, 26}, validate); 9817bbb224Svarconst // Empty input. 9917bbb224Svarconst test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array<int, 0>{}, validate); 10017bbb224Svarconst // Single-element input. 10117bbb224Svarconst test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array{5}, validate); 10217bbb224Svarconst } 10317bbb224Svarconst 10417bbb224Svarconst template <template <class ...> class Container> 10517bbb224Svarconst constexpr void test_sequence_container_move_only() { 10617bbb224Svarconst MoveOnly input[5]; 10717bbb224Svarconst std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5}); 10817bbb224Svarconst 10917bbb224Svarconst [[maybe_unused]] Container<MoveOnly> c(std::from_range, in); 11017bbb224Svarconst } 11117bbb224Svarconst 11217bbb224Svarconst template <class Iter, 11317bbb224Svarconst class Sent, 11417bbb224Svarconst class Alloc, 11517bbb224Svarconst class ValidateFunc> 11617bbb224Svarconst constexpr void test_vector_bool(ValidateFunc validate) { 11717bbb224Svarconst // Normal input. 11817bbb224Svarconst test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>( 11917bbb224Svarconst std::array{true, false, false, true, false, true, true, true, false, true}, validate); 12017bbb224Svarconst // Empty input. 12117bbb224Svarconst test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(std::array<bool, 0>{}, validate); 12217bbb224Svarconst // Single-element input. 12317bbb224Svarconst test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(std::array{true}, validate); 12417bbb224Svarconst } 12517bbb224Svarconst 12617bbb224Svarconst template <template <class ...> class Container> 12717bbb224Svarconst void test_exception_safety_throwing_copy() { 12817bbb224Svarconst #if !defined(TEST_HAS_NO_EXCEPTIONS) 129d0b51657Svarconst constexpr int ThrowOn = 3; 130d0b51657Svarconst using T = ThrowingCopy<ThrowOn>; 131d0b51657Svarconst test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) { 132d0b51657Svarconst [[maybe_unused]] Container<T> c(std::from_range, std::ranges::subrange(from, to)); 133d0b51657Svarconst }); 13417bbb224Svarconst #endif 13517bbb224Svarconst } 13617bbb224Svarconst 13717bbb224Svarconst template <template <class ...> class Container, class T> 13817bbb224Svarconst void test_exception_safety_throwing_allocator() { 13917bbb224Svarconst #if !defined(TEST_HAS_NO_EXCEPTIONS) 14017bbb224Svarconst T in[] = {0, 1}; 14117bbb224Svarconst 14217bbb224Svarconst try { 14317bbb224Svarconst ThrowingAllocator<T> alloc; 14417bbb224Svarconst 14517bbb224Svarconst globalMemCounter.reset(); 14617bbb224Svarconst Container<T, ThrowingAllocator<T>> c(std::from_range, in, alloc); 14717bbb224Svarconst assert(false); // The constructor call above should throw. 14817bbb224Svarconst 14917bbb224Svarconst } catch (int) { 15017bbb224Svarconst assert(globalMemCounter.new_called == globalMemCounter.delete_called); 15117bbb224Svarconst } 15217bbb224Svarconst #endif 15317bbb224Svarconst } 15417bbb224Svarconst 15517bbb224Svarconst #endif // SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H 156