| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SUPPORT_FROM_RANGE_HELPERS_H |
| #define SUPPORT_FROM_RANGE_HELPERS_H |
| |
| #include <array> |
| #include <cstddef> |
| #include <iterator> |
| #include <type_traits> |
| #include <vector> |
| |
| #include "min_allocator.h" |
| #include "test_allocator.h" |
| #include "test_iterators.h" |
| #include "test_macros.h" |
| #include "type_algorithms.h" |
| |
| struct Empty {}; |
| |
| template <class T> |
| struct InputRange { |
| cpp20_input_iterator<T*> begin(); |
| sentinel_wrapper<cpp20_input_iterator<T*>> end(); |
| }; |
| |
| template <class Iter, class Sent, std::ranges::input_range Range> |
| constexpr auto wrap_input(Range&& input) { |
| auto b = Iter(std::ranges::begin(input)); |
| auto e = Sent(Iter(std::ranges::end(input))); |
| return std::ranges::subrange(std::move(b), std::move(e)); |
| } |
| |
| template <class Iter, class Sent, class T, std::size_t N> |
| constexpr auto wrap_input(std::array<T, N>& input) { |
| auto b = Iter(input.data()); |
| auto e = Sent(Iter(input.data() + input.size())); |
| return std::ranges::subrange(std::move(b), std::move(e)); |
| } |
| |
| template <class Iter, class Sent, class T> |
| constexpr auto wrap_input(std::vector<T>& input) { |
| auto b = Iter(input.data()); |
| auto e = Sent(Iter(input.data() + input.size())); |
| return std::ranges::subrange(std::move(b), std::move(e)); |
| } |
| |
| struct KeyValue { |
| int key; // Only the key is considered for equality comparison. |
| char value; // Allows distinguishing equivalent instances. |
| |
| bool operator<(const KeyValue& other) const { return key < other.key; } |
| bool operator==(const KeyValue& other) const { return key == other.key; } |
| }; |
| |
| template <> |
| struct std::hash<KeyValue> { |
| std::size_t operator()(const KeyValue& kv) const { |
| return kv.key; |
| } |
| }; |
| |
| #if !defined(TEST_HAS_NO_EXCEPTIONS) |
| |
| template <class T> |
| struct ThrowingAllocator { |
| using value_type = T; |
| using char_type = T; |
| using is_always_equal = std::false_type; |
| |
| ThrowingAllocator() = default; |
| |
| template <class U> |
| ThrowingAllocator(const ThrowingAllocator<U>&) {} |
| |
| T* allocate(std::size_t) { throw 1; } |
| void deallocate(T*, std::size_t) {} |
| |
| template <class U> |
| friend bool operator==(const ThrowingAllocator&, const ThrowingAllocator<U>&) { |
| return true; |
| } |
| }; |
| #endif |
| |
| template <class T, class Func> |
| constexpr void for_all_iterators_and_allocators(Func f) { |
| using Iterators = types::type_list< |
| cpp20_input_iterator<T*>, |
| forward_iterator<T*>, |
| bidirectional_iterator<T*>, |
| random_access_iterator<T*>, |
| contiguous_iterator<T*>, |
| T* |
| >; |
| |
| types::for_each(Iterators{}, [=]<class Iter>() { |
| f.template operator()<Iter, sentinel_wrapper<Iter>, std::allocator<T>>(); |
| f.template operator()<Iter, sentinel_wrapper<Iter>, test_allocator<T>>(); |
| f.template operator()<Iter, sentinel_wrapper<Iter>, min_allocator<T>>(); |
| f.template operator()<Iter, sentinel_wrapper<Iter>, safe_allocator<T>>(); |
| |
| if constexpr (std::sentinel_for<Iter, Iter>) { |
| f.template operator()<Iter, Iter, std::allocator<T>>(); |
| f.template operator()<Iter, Iter, test_allocator<T>>(); |
| f.template operator()<Iter, Iter, min_allocator<T>>(); |
| f.template operator()<Iter, Iter, safe_allocator<T>>(); |
| } |
| }); |
| } |
| |
| #endif // SUPPORT_FROM_RANGE_HELPERS_H |