245 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// REQUIRES: std-at-least-c++2310 11// <ranges>12 13// template<input_range R>14// requires constructible_from<V, views::all_t<R>> &&15// constructible_from<Pattern, single_view<range_value_t<InnerRng>>>16// constexpr explicit join_with_view(R&& r, range_value_t<InnerRng> e);17 18#include <ranges>19 20#include <algorithm>21#include <array>22#include <cassert>23#include <type_traits>24#include <utility>25 26#include "../types.h"27#include "test_iterators.h"28#include "test_range.h"29 30struct MoveOnlyInt {31 MoveOnlyInt() = default;32 MoveOnlyInt(MoveOnlyInt&&) = default;33 MoveOnlyInt& operator=(MoveOnlyInt&&) = default;34 35 constexpr MoveOnlyInt(int val) : val_(val) {}36 constexpr operator int() const { return val_; }37 38 int val_ = 0;39};40 41template <>42struct std::common_type<MoveOnlyInt, int> {43 using type = int;44};45 46template <>47struct std::common_type<int, MoveOnlyInt> {48 using type = int;49};50 51struct OutputView : std::ranges::view_base {52 using It = cpp20_output_iterator<int*>;53 It begin() const;54 sentinel_wrapper<It> end() const;55};56 57static_assert(std::ranges::output_range<OutputView, int>);58static_assert(std::ranges::view<OutputView>);59 60struct InputRange {61 using It = cpp20_input_iterator<int*>;62 It begin() const;63 sentinel_wrapper<It> end() const;64};65 66struct InputView : InputRange, std::ranges::view_base {};67 68static_assert(std::ranges::input_range<InputRange>);69static_assert(std::ranges::input_range<const InputRange>);70static_assert(std::ranges::view<InputView>);71static_assert(std::ranges::input_range<InputView>);72static_assert(std::ranges::input_range<const InputView>);73 74class View : public std::ranges::view_base {75 using OuterRange = std::array<std::array<MoveOnlyInt, 2>, 3>;76 77 static constexpr OuterRange range_on_input_view = {{{1, 1}, {1, 1}, {1, 1}}};78 static constexpr OuterRange range_on_ref_input_range = {{{2, 2}, {2, 2}, {2, 2}}};79 static constexpr OuterRange range_on_const_ref_input_range = {{{3, 3}, {3, 3}, {3, 3}}};80 static constexpr OuterRange range_on_owning_input_range = {{{4, 4}, {4, 4}, {4, 4}}};81 82 const OuterRange* r_;83 84public:85 // Those functions should never be called in this test.86 View(View&&) { assert(false); }87 View(OutputView) { assert(false); }88 View& operator=(View&&) {89 assert(false);90 return *this;91 }92 93 constexpr explicit View(InputView) : r_(&range_on_input_view) {}94 constexpr explicit View(InputRange) = delete;95 constexpr explicit View(std::ranges::ref_view<InputRange>) : r_(&range_on_ref_input_range) {}96 constexpr explicit View(std::ranges::ref_view<const InputRange>) : r_(&range_on_const_ref_input_range) {}97 constexpr explicit View(std::ranges::owning_view<InputRange>) : r_(&range_on_owning_input_range) {}98 99 constexpr auto begin() const { return r_->begin(); }100 constexpr auto end() const { return r_->end(); }101};102 103static_assert(std::ranges::input_range<View>);104static_assert(std::ranges::input_range<const View>);105 106class Pattern : public std::ranges::view_base {107 int val_;108 109public:110 // Those functions should never be called in this test.111 Pattern(Pattern&&) { assert(false); }112 template <class T>113 Pattern(const std::ranges::single_view<T>&) {114 assert(false);115 }116 Pattern& operator=(Pattern&&) {117 assert(false);118 return *this;119 }120 121 template <class T>122 constexpr explicit Pattern(std::ranges::single_view<T>&& v) : val_(v[0]) {}123 124 constexpr const int* begin() const { return &val_; }125 constexpr const int* end() const { return &val_ + 1; }126};127 128static_assert(std::ranges::forward_range<Pattern>);129static_assert(std::ranges::forward_range<const Pattern>);130 131constexpr void test_ctor_with_view_and_element() {132 // Check construction from `r` and `e`, when `r` models `std::ranges::view`133 134 { // `r` and `e` are glvalues135 InputView r;136 int e = 0;137 std::ranges::join_with_view<View, Pattern> jwv(r, e);138 assert(std::ranges::equal(jwv, std::array{1, 1, 0, 1, 1, 0, 1, 1}));139 }140 141 { // `r` and `e` are const glvalues142 const InputView r;143 const int e = 1;144 std::ranges::join_with_view<View, Pattern> jwv(r, e);145 assert(std::ranges::equal(jwv, std::array{1, 1, 1, 1, 1, 1, 1, 1}));146 }147 148 { // `r` and `e` are prvalues149 std::ranges::join_with_view<View, Pattern> jwv(InputView{}, MoveOnlyInt{2});150 assert(std::ranges::equal(jwv, std::array{1, 1, 2, 1, 1, 2, 1, 1}));151 }152 153 { // `r` and `e` are xvalues154 InputView r;155 MoveOnlyInt e = 3;156 std::ranges::join_with_view<View, Pattern> jwv(std::move(r), std::move(e));157 assert(std::ranges::equal(jwv, std::array{1, 1, 3, 1, 1, 3, 1, 1}));158 }159 160 // Check explicitness161 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputView, MoveOnlyInt>);162 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputView, int>);163 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputView&, int&>);164 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, const InputView, const int>);165 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, const InputView&, const int&>);166}167 168constexpr void test_ctor_with_non_view_and_element() {169 // Check construction from `r` and `e`, when `r` does not model `std::ranges::view`170 171 { // `r` and `e` are glvalues172 InputRange r;173 int e = 0;174 std::ranges::join_with_view<View, Pattern> jwv(r, e);175 assert(std::ranges::equal(jwv, std::array{2, 2, 0, 2, 2, 0, 2, 2}));176 }177 178 { // `r` and `e` are const glvalues179 const InputRange r;180 const int e = 1;181 std::ranges::join_with_view<View, Pattern> jwv(r, e);182 assert(std::ranges::equal(jwv, std::array{3, 3, 1, 3, 3, 1, 3, 3}));183 }184 185 { // `r` and `e` are prvalues186 std::ranges::join_with_view<View, Pattern> jwv(InputRange{}, MoveOnlyInt{2});187 assert(std::ranges::equal(jwv, std::array{4, 4, 2, 4, 4, 2, 4, 4}));188 }189 190 { // `r` and `e` are xvalues191 InputRange r;192 MoveOnlyInt e = 3;193 std::ranges::join_with_view<View, Pattern> jwv(std::move(r), std::move(e));194 assert(std::ranges::equal(jwv, std::array{4, 4, 3, 4, 4, 3, 4, 4}));195 }196 197 // Check explicitness198 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputRange, MoveOnlyInt>);199 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputRange, int>);200 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputRange&, int&>);201 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, const InputRange&, const int&>);202}203 204constexpr void test_constraints() {205 { // `R` is not an input range206 using R = OutputView;207 static_assert(!std::ranges::input_range<R>);208 static_assert(std::constructible_from<View, std::views::all_t<R>>);209 static_assert(std::constructible_from<Pattern, std::ranges::single_view<int>>);210 static_assert(!std::constructible_from<std::ranges::join_with_view<View, Pattern>, R, int>);211 }212 213 { // `V` is not constructible from `views::all_t<R>`214 using R = test_range<cpp20_input_iterator>;215 static_assert(std::ranges::input_range<R>);216 static_assert(!std::constructible_from<View, std::views::all_t<R>>);217 static_assert(std::constructible_from<Pattern, std::ranges::single_view<int>>);218 static_assert(!std::constructible_from<std::ranges::join_with_view<View, Pattern>, R, int>);219 }220 221 { // `Pattern` is not constructible from `single_view<range_value_t<InnerRng>>`222 using R = InputView;223 using Pat = test_view<forward_iterator>;224 static_assert(std::ranges::input_range<R>);225 static_assert(std::constructible_from<View, std::views::all_t<R>>);226 static_assert(!std::constructible_from<Pat, std::ranges::single_view<int>>);227 static_assert(!std::constructible_from<std::ranges::join_with_view<View, Pat>, R, int>);228 }229}230 231constexpr bool test() {232 test_ctor_with_view_and_element();233 test_ctor_with_non_view_and_element();234 test_constraints();235 236 return true;237}238 239int main(int, char**) {240 test();241 static_assert(test());242 243 return 0;244}245