brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.1 KiB · da53bfa Raw
361 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// std::views::join_with_view14 15#include <ranges>16 17#include <memory>18#include <span>19#include <string_view>20#include <utility>21 22#include "test_iterators.h"23 24template <class View, class T>25concept CanBePiped = requires(View&& view, T&& t) {26  { std::forward<View>(view) | std::forward<T>(t) };27};28 29struct Range : std::ranges::view_base {30  using Iterator = forward_iterator<std::string_view*>;31  using Sentinel = sentinel_wrapper<Iterator>;32  constexpr explicit Range(std::string_view* b, std::string_view* e) : begin_(b), end_(e) {}33  constexpr Iterator begin() const { return Iterator(begin_); }34  constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }35 36private:37  std::string_view* begin_;38  std::string_view* end_;39};40 41struct Pattern : std::ranges::view_base {42  using Iterator = forward_iterator<const char*>;43  using Sentinel = sentinel_wrapper<Iterator>;44  static constexpr std::string_view pat{", "};45 46  constexpr Pattern() = default;47  constexpr Iterator begin() const { return Iterator(pat.data()); }48  constexpr Sentinel end() const { return Sentinel(Iterator(pat.data() + pat.size())); }49};50 51struct NonCopyablePattern : Pattern {52  NonCopyablePattern(const NonCopyablePattern&) = delete;53};54 55template <typename View>56constexpr void compareViews(View v, std::string_view list) {57  auto b1 = v.begin();58  auto e1 = v.end();59  auto b2 = list.begin();60  auto e2 = list.end();61  for (; b1 != e1 && b2 != e2; ++b1, ++b2) {62    assert(*b1 == *b2);63  }64  assert(b1 == e1);65  assert(b2 == e2);66}67 68constexpr int absoluteValue(int x) { return x < 0 ? -x : x; }69 70template <class T>71constexpr const T&& asConstRvalue(T&& t) {72  return static_cast<const T&&>(t);73}74 75constexpr void test_adaptor_with_pattern(std::span<std::string_view> buff) {76  // Test `views::join_with(pattern)(v)`77  {78    using Result = std::ranges::join_with_view<Range, Pattern>;79    const Range range(buff.data(), buff.data() + buff.size());80    Pattern pattern;81 82    {83      // 'views::join_with(pattern)' - &&84      std::same_as<Result> decltype(auto) result = std::views::join_with(pattern)(range);85      compareViews(result, "abcd, ef, ghij, kl");86    }87    {88      // 'views::join_with(pattern)' - const&&89      std::same_as<Result> decltype(auto) result = asConstRvalue(std::views::join_with(pattern))(range);90      compareViews(result, "abcd, ef, ghij, kl");91    }92    {93      // 'views::join_with(pattern)' - &94      auto partial                               = std::views::join_with(pattern);95      std::same_as<Result> decltype(auto) result = partial(range);96      compareViews(result, "abcd, ef, ghij, kl");97    }98    {99      // 'views::join_with(pattern)' - const&100      auto const partial                         = std::views::join_with(pattern);101      std::same_as<Result> decltype(auto) result = partial(range);102      compareViews(result, "abcd, ef, ghij, kl");103    }104  }105 106  // Test `v | views::join_with(pattern)`107  {108    using Result = std::ranges::join_with_view<Range, Pattern>;109    const Range range(buff.data(), buff.data() + buff.size());110    Pattern pattern;111 112    {113      // 'views::join_with(pattern)' - &&114      std::same_as<Result> decltype(auto) result = range | std::views::join_with(pattern);115      compareViews(result, "abcd, ef, ghij, kl");116    }117    {118      // 'views::join_with(pattern)' - const&&119      std::same_as<Result> decltype(auto) result = range | asConstRvalue(std::views::join_with(pattern));120      compareViews(result, "abcd, ef, ghij, kl");121    }122    {123      // 'views::join_with(pattern)' - &124      auto partial                               = std::views::join_with(pattern);125      std::same_as<Result> decltype(auto) result = range | partial;126      compareViews(result, "abcd, ef, ghij, kl");127    }128    {129      // 'views::join_with(pattern)' - const&130      auto const partial                         = std::views::join_with(pattern);131      std::same_as<Result> decltype(auto) result = range | partial;132      compareViews(result, "abcd, ef, ghij, kl");133    }134  }135 136  // Test `views::join_with(v, pattern)` range adaptor object137  {138    using Result = std::ranges::join_with_view<Range, Pattern>;139    const Range range(buff.data(), buff.data() + buff.size());140    Pattern pattern;141 142    {143      // 'views::join_with' - &&144      auto range_adaptor                         = std::views::join_with;145      std::same_as<Result> decltype(auto) result = std::move(range_adaptor)(range, pattern);146      compareViews(result, "abcd, ef, ghij, kl");147    }148    {149      // 'views::join_with' - const&&150      const auto range_adaptor                   = std::views::join_with;151      std::same_as<Result> decltype(auto) result = std::move(range_adaptor)(range, pattern);152      compareViews(result, "abcd, ef, ghij, kl");153    }154    {155      // 'views::join_with' - &156      auto range_adaptor                         = std::views::join_with;157      std::same_as<Result> decltype(auto) result = range_adaptor(range, pattern);158      compareViews(result, "abcd, ef, ghij, kl");159    }160    {161      // 'views::join_with' - const&162      const auto range_adaptor                   = std::views::join_with;163      std::same_as<Result> decltype(auto) result = range_adaptor(range, pattern);164      compareViews(result, "abcd, ef, ghij, kl");165    }166  }167 168  // Test `adaptor | views::join_with(pattern)`169  {170    auto pred    = [](std::string_view s) { return s.size() >= 3; };171    using Result = std::ranges::join_with_view<std::ranges::filter_view<Range, decltype(pred)>, Pattern>;172    const Range range(buff.data(), buff.data() + buff.size());173    Pattern pattern;174 175    {176      std::same_as<Result> decltype(auto) result = range | std::views::filter(pred) | std::views::join_with(pattern);177      compareViews(result, "abcd, ghij");178    }179    {180      const auto partial                         = std::views::filter(pred) | std::views::join_with(pattern);181      std::same_as<Result> decltype(auto) result = range | partial;182      compareViews(result, "abcd, ghij");183    }184  }185}186 187constexpr void test_adaptor_with_single_element(std::span<std::string_view> buff) {188  // Test `views::join_with(element)(v)`189  {190    using Result = std::ranges::join_with_view<Range, std::ranges::single_view<char>>;191    const Range range(buff.data(), buff.data() + buff.size());192    const char element = '.';193 194    {195      // 'views::join_with(element)' - &&196      std::same_as<Result> decltype(auto) result = std::views::join_with(element)(range);197      compareViews(result, "abcd.ef.ghij.kl");198    }199    {200      // 'views::join_with(element)' - const&&201      std::same_as<Result> decltype(auto) result = asConstRvalue(std::views::join_with(element))(range);202      compareViews(result, "abcd.ef.ghij.kl");203    }204    {205      // 'views::join_with(element)' - &206      auto partial                               = std::views::join_with(element);207      std::same_as<Result> decltype(auto) result = partial(range);208      compareViews(result, "abcd.ef.ghij.kl");209    }210    {211      // 'views::join_with(element)' - const&212      const auto partial                         = std::views::join_with(element);213      std::same_as<Result> decltype(auto) result = partial(range);214      compareViews(result, "abcd.ef.ghij.kl");215    }216  }217 218  // Test `v | views::join_with(element)`219  {220    using Result = std::ranges::join_with_view<Range, std::ranges::single_view<char>>;221    const Range range(buff.data(), buff.data() + buff.size());222    const char element = '.';223 224    {225      // 'views::join_with(element)' - &&226      std::same_as<Result> decltype(auto) result = range | std::views::join_with(element);227      compareViews(result, "abcd.ef.ghij.kl");228    }229    {230      // 'views::join_with(element)' - const&&231      std::same_as<Result> decltype(auto) result = range | asConstRvalue(std::views::join_with(element));232      compareViews(result, "abcd.ef.ghij.kl");233    }234    {235      // 'views::join_with(element)' - &236      auto partial                               = std::views::join_with(element);237      std::same_as<Result> decltype(auto) result = range | partial;238      compareViews(result, "abcd.ef.ghij.kl");239    }240    {241      // 'views::join_with(element)' - const&242      const auto partial                         = std::views::join_with(element);243      std::same_as<Result> decltype(auto) result = range | partial;244      compareViews(result, "abcd.ef.ghij.kl");245    }246  }247 248  // Test `views::join_with(v, element)` range adaptor object249  {250    using Result = std::ranges::join_with_view<Range, std::ranges::single_view<char>>;251    const Range range(buff.data(), buff.data() + buff.size());252    const char element = '.';253 254    {255      // 'views::join_with' - &&256      auto range_adaptor                         = std::views::join_with;257      std::same_as<Result> decltype(auto) result = std::move(range_adaptor)(range, element);258      compareViews(result, "abcd.ef.ghij.kl");259    }260    {261      // 'views::join_with' - const&&262      const auto range_adaptor                   = std::views::join_with;263      std::same_as<Result> decltype(auto) result = std::move(range_adaptor)(range, element);264      compareViews(result, "abcd.ef.ghij.kl");265    }266    {267      // 'views::join_with' - &268      auto range_adaptor                         = std::views::join_with;269      std::same_as<Result> decltype(auto) result = range_adaptor(range, element);270      compareViews(result, "abcd.ef.ghij.kl");271    }272    {273      // 'views::join_with' - const&274      const auto range_adaptor                   = std::views::join_with;275      std::same_as<Result> decltype(auto) result = range_adaptor(range, element);276      compareViews(result, "abcd.ef.ghij.kl");277    }278  }279 280  // Test `adaptor | views::join_with(element)`281  {282    auto pred = [](std::string_view s) { return s.size() >= 3; };283    using Result =284        std::ranges::join_with_view<std::ranges::filter_view<Range, decltype(pred)>, std::ranges::single_view<char>>;285    const Range range(buff.data(), buff.data() + buff.size());286    const char element = '.';287 288    {289      std::same_as<Result> decltype(auto) result = range | std::views::filter(pred) | std::views::join_with(element);290      compareViews(result, "abcd.ghij");291    }292    {293      const auto partial                         = std::views::filter(pred) | std::views::join_with(element);294      std::same_as<Result> decltype(auto) result = range | partial;295      compareViews(result, "abcd.ghij");296    }297  }298}299 300constexpr bool test() {301  std::string_view buff[] = {"abcd", "ef", "ghij", "kl"};302 303  // Test range adaptor object304  {305    using RangeAdaptorObject = decltype(std::views::join_with);306    static_assert(std::is_const_v<RangeAdaptorObject>);307 308    // The type of a customization point object, ignoring cv-qualifiers, shall model semiregular309    static_assert(std::semiregular<std::remove_const<RangeAdaptorObject>>);310  }311 312  test_adaptor_with_pattern(buff);313  test_adaptor_with_single_element(buff);314 315  // Test that one can call std::views::join_with with arbitrary stuff, as long as we316  // don't try to actually complete the call by passing it a range.317  //318  // That makes no sense and we can't do anything with the result, but it's valid.319  {320    long array[3]                 = {1, 2, 3};321    [[maybe_unused]] auto partial = std::views::join_with(std::move(array));322  }323 324  // Test SFINAE friendliness325  {326    struct NotAView {};327 328    static_assert(!CanBePiped<Range, decltype(std::views::join_with)>);329    static_assert(CanBePiped<Range, decltype(std::views::join_with(Pattern{}))>);330    static_assert(CanBePiped<Range, decltype(std::views::join_with('.'))>);331    static_assert(!CanBePiped<NotAView, decltype(std::views::join_with(Pattern{}))>);332    static_assert(!CanBePiped<NotAView, decltype(std::views::join_with('.'))>);333    static_assert(!CanBePiped<std::initializer_list<char>, decltype(std::views::join_with(Pattern{}))>);334    static_assert(!CanBePiped<std::initializer_list<char>, decltype(std::views::join_with('.'))>);335    static_assert(!CanBePiped<Range, decltype(std::views::join_with(NotAView{}))>);336 337    static_assert(!std::is_invocable_v<decltype(std::views::join_with)>);338    static_assert(!std::is_invocable_v<decltype(std::views::join_with), Pattern, Range>);339    static_assert(!std::is_invocable_v<decltype(std::views::join_with), char, Range>);340    static_assert(std::is_invocable_v<decltype(std::views::join_with), Range, Pattern>);341    static_assert(std::is_invocable_v<decltype(std::views::join_with), Range, char>);342    static_assert(!std::is_invocable_v<decltype(std::views::join_with), Range, Pattern, Pattern>);343    static_assert(!std::is_invocable_v<decltype(std::views::join_with), Range, char, char>);344    static_assert(!std::is_invocable_v<decltype(std::views::join_with), NonCopyablePattern>);345  }346 347  {348    static_assert(std::is_same_v<decltype(std::ranges::views::join_with), decltype(std::views::join_with)>);349    assert(std::addressof(std::ranges::views::join_with) == std::addressof(std::views::join_with));350  }351 352  return true;353}354 355int main(int, char**) {356  test();357  static_assert(test());358 359  return 0;360}361