226 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// constexpr decltype(auto) operator*() const;14 15#include <ranges>16 17#include <array>18#include <cassert>19#include <cstddef>20#include <string>21#include <string_view>22#include <type_traits>23#include <utility>24#include <vector>25 26#include "../types.h"27 28struct ProxyRef {29 int& val;30};31 32class CommonProxyRef {33public:34 constexpr CommonProxyRef(ProxyRef i) : val(i.val) {}35 constexpr CommonProxyRef(int i) : val(i) {}36 37 constexpr int get() const { return val; }38 39private:40 int val;41};42 43template <template <class> class TQual, template <class> class UQual>44struct std::basic_common_reference<ProxyRef, int, TQual, UQual> {45 using type = CommonProxyRef;46};47 48template <template <class> class TQual, template <class> class UQual>49struct std::basic_common_reference<int, ProxyRef, TQual, UQual> {50 using type = CommonProxyRef;51};52 53static_assert(std::common_reference_with<int&, ProxyRef>);54static_assert(std::common_reference_with<int&, CommonProxyRef>);55 56class ProxyIter {57public:58 using value_type = int;59 using difference_type = std::ptrdiff_t;60 61 constexpr ProxyIter() : ptr_(nullptr) {}62 constexpr explicit ProxyIter(int* p) : ptr_(p) {}63 64 constexpr ProxyRef operator*() const { return ProxyRef{*ptr_}; }65 66 constexpr ProxyIter& operator++() {67 ++ptr_;68 return *this;69 }70 71 constexpr ProxyIter operator++(int) {72 ProxyIter tmp = *this;73 ++ptr_;74 return tmp;75 }76 77 constexpr bool operator==(const ProxyIter& other) const { return ptr_ == other.ptr_; }78 79private:80 int* ptr_;81};82 83static_assert(std::forward_iterator<ProxyIter>);84 85constexpr bool test() {86 { // Result of `operator*` is (maybe const) lvalue reference87 using V = std::ranges::owning_view<std::vector<std::string>>;88 using Pattern = std::ranges::owning_view<std::string>;89 using JWV = std::ranges::join_with_view<V, Pattern>;90 91 JWV jwv(V{{"ab", "cd", "ef"}}, Pattern{"><"});92 93 {94 auto it = jwv.begin();95 std::same_as<char&> decltype(auto) v_ref = *std::as_const(it);96 assert(v_ref == 'a');97 std::ranges::advance(it, 2);98 std::same_as<char&> decltype(auto) pattern_ref = *it;99 assert(pattern_ref == '>');100 }101 102 {103 auto cit = std::as_const(jwv).begin();104 std::same_as<const char&> decltype(auto) cv_ref = *cit;105 assert(cv_ref == 'a');106 std::ranges::advance(cit, 3);107 std::same_as<const char&> decltype(auto) cpattern_ref = *std::as_const(cit);108 assert(cpattern_ref == '<');109 }110 }111 112 { // Result of `operator*` is const lvalue reference113 using V = std::ranges::owning_view<std::vector<std::string_view>>;114 using Pattern = std::string_view;115 using JWV = std::ranges::join_with_view<V, Pattern>;116 117 JWV jwv(V{{"123", "456", "789"}}, Pattern{"._."});118 119 {120 auto it = jwv.begin();121 std::same_as<const char&> decltype(auto) v_ref = *it;122 assert(v_ref == '1');123 std::ranges::advance(it, 3);124 std::same_as<const char&> decltype(auto) pattern_ref = *std::as_const(it);125 assert(pattern_ref == '.');126 }127 128 {129 auto cit = std::as_const(jwv).begin();130 std::same_as<const char&> decltype(auto) cv_ref = *std::as_const(cit);131 assert(cv_ref == '1');132 std::ranges::advance(cit, 4);133 std::same_as<const char&> decltype(auto) cpattern_ref = *cit;134 assert(cpattern_ref == '_');135 }136 }137 138 { // Result of `operator*` is prvalue139 using V = std::vector<std::string_view>;140 using Pattern = RvalueVector<char>;141 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, std::ranges::owning_view<Pattern>>;142 143 JWV jwv(V{"x^2", "y^2", "z^2"}, Pattern{{' ', '+', ' '}});144 145 {146 auto it = jwv.begin();147 std::same_as<char> decltype(auto) v_ref = *std::as_const(it);148 assert(v_ref == 'x');149 std::ranges::advance(it, 3);150 std::same_as<char> decltype(auto) pattern_ref = *it;151 assert(pattern_ref == ' ');152 }153 154 {155 auto cit = std::as_const(jwv).begin();156 std::same_as<char> decltype(auto) cv_ref = *cit;157 assert(cv_ref == 'x');158 std::ranges::advance(cit, 4);159 std::same_as<char> decltype(auto) cpattern_ref = *std::as_const(cit);160 assert(cpattern_ref == '+');161 }162 }163 164 { // Result of `operator*` is (maybe const) rvalue reference165 using Inner = std::ranges::as_rvalue_view<std::ranges::owning_view<std::string>>;166 using V = std::ranges::owning_view<std::vector<Inner>>;167 using Pattern = std::ranges::as_rvalue_view<std::ranges::owning_view<std::array<char, 2>>>;168 using JWV = std::ranges::join_with_view<V, Pattern>;169 170 std::vector<Inner> vec;171 vec.emplace_back(Inner{{"x*y"}});172 vec.emplace_back(Inner{{"y*z"}});173 vec.emplace_back(Inner{{"z*x"}});174 JWV jwv(V(std::move(vec)), Pattern(std::array{',', ' '}));175 176 {177 auto it = jwv.begin();178 std::same_as<char&&> decltype(auto) v_ref = *it;179 assert(v_ref == 'x');180 std::ranges::advance(it, 3);181 std::same_as<char&&> decltype(auto) pattern_ref = *std::as_const(it);182 assert(pattern_ref == ',');183 }184 185 {186 auto cit = std::as_const(jwv).begin();187 std::same_as<const char&&> decltype(auto) cv_ref = *std::as_const(cit);188 assert(cv_ref == 'x');189 std::ranges::advance(cit, 4);190 std::same_as<const char&&> decltype(auto) cpattern_ref = *cit;191 assert(cpattern_ref == ' ');192 }193 }194 195 { // Result of `operator*` is type different from range_reference_t<InnerRng> and range_reference_t<Pattern>196 using Inner = std::vector<int>;197 using V = std::vector<Inner>;198 using Pattern = std::ranges::subrange<ProxyIter, ProxyIter>;199 using JWV = std::ranges::join_with_view<std::ranges::owning_view<V>, Pattern>;200 201 static_assert(!std::same_as<std::ranges::range_reference_t<V>, std::ranges::range_reference_t<JWV>>);202 static_assert(!std::same_as<std::ranges::range_reference_t<Pattern>, std::ranges::range_reference_t<JWV>>);203 204 std::array<int, 2> pattern = {-1, -1};205 Pattern pattern_as_subrange(ProxyIter{pattern.data()}, ProxyIter{pattern.data() + pattern.size()});206 207 JWV jwv(V{Inner{1, 1}, Inner{2, 2}, Inner{3, 3}}, pattern_as_subrange);208 209 auto it = jwv.begin();210 std::same_as<CommonProxyRef> decltype(auto) v_ref = *it;211 assert(v_ref.get() == 1);212 std::ranges::advance(it, 7);213 std::same_as<CommonProxyRef> decltype(auto) pattern_ref = *std::as_const(it);214 assert(pattern_ref.get() == -1);215 }216 217 return true;218}219 220int main(int, char**) {221 test();222 static_assert(test());223 224 return 0;225}226