blob: 2918d4f86afb5aed53c6bb7e4c1b184ad7216653 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// clang-cl and cl currently don't support [[no_unique_address]]
// XFAIL: msvc
// class lazy_split_view {
// _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
// _LIBCPP_NO_UNIQUE_ADDRESS _Pattern __pattern_ = _Pattern();
// };
#include <ranges>
#include <string_view>
#include "test_iterators.h"
// Verify the optimization that, if `View` is a forward range, the `lazy_split_view` itself doesn't store the `current`
// iterator (instead, it's stored in the `outer-iterator`).
//
// Note that the Standard marks all data members of `lazy_split_view` as "exposition only", so this test has to be
// libc++-specific.
namespace test1 {
using SplitView = std::ranges::lazy_split_view<std::string_view, std::string_view>;
// The `lazy_split_view` only stores the `View` and the `Pattern`, not an iterator.
static_assert(sizeof(SplitView) == sizeof(std::string_view) * 2);
} // namespace test1
// Verify the optimization that, if `View` is an input range, the `outer-iterator` doesn't store the `current` iterator
// (instead, it's stored in the `lazy_split_view` itself).
//
// Note that the Standard marks all data members of `outer-iterator` as "exposition only", so this test has to be
// libc++-specific.
namespace test2 {
struct InputView : std::ranges::view_base {
int x;
cpp20_input_iterator<int*> begin() const;
sentinel_wrapper<cpp20_input_iterator<int*>> end() const;
};
static_assert( std::ranges::input_range<InputView>);
static_assert(!std::ranges::forward_range<InputView>);
static_assert( std::ranges::view<InputView>);
struct TinyView : std::ranges::view_base {
int x;
int* begin() const;
int* end() const;
constexpr static std::size_t size() { return 1; }
};
static_assert( std::ranges::forward_range<TinyView>);
static_assert( std::ranges::__tiny_range<TinyView>);
static_assert( std::ranges::view<TinyView>);
using SplitView = std::ranges::lazy_split_view<InputView, TinyView>;
using OuterIter = std::ranges::iterator_t<SplitView>;
// The `outer-iterator` only stores a pointer to the parent and a boolean (aligned to the size of a pointer), not an
// iterator.
static_assert(sizeof(OuterIter) == sizeof(void*) * 2);
} // namespace test2
// Verify the libc++-specific optimization that empty `View` and `Pattern` use the `[[no_unique_address]]` attribute.
// Both `View` and `Pattern` are forward views.
namespace test3 {
struct EmptyView1 : std::ranges::view_base {
int* begin() const;
int* end() const;
};
static_assert( std::ranges::forward_range<EmptyView1>);
static_assert( std::ranges::view<EmptyView1>);
// Note: it's important to inherit `EmptyView1` and `EmptyView2` from different bases, otherwise they still cannot share
// the same address regardless of whether `[[no_unique_address]]` is used.
struct EmptyView2 : std::ranges::view_interface<EmptyView2> {
int* begin() const;
int* end() const;
};
static_assert( std::ranges::forward_range<EmptyView2>);
static_assert( std::ranges::view<EmptyView2>);
static_assert(sizeof(std::ranges::lazy_split_view<EmptyView1, EmptyView2>) == 1);
} // namespace test3
// Verify the libc++-specific optimization that empty `View` and `Pattern` use the `[[no_unique_address]]` attribute.
// `View` is an input view and `Pattern` is a tiny view.
namespace test4 {
struct EmptyInputView : std::ranges::view_base {
cpp20_input_iterator<int*> begin() const;
sentinel_wrapper<cpp20_input_iterator<int*>> end() const;
};
static_assert( std::ranges::input_range<EmptyInputView>);
static_assert(!std::ranges::forward_range<EmptyInputView>);
static_assert( std::ranges::view<EmptyInputView>);
struct EmptyTinyView : std::ranges::view_base {
int* begin() const;
int* end() const;
constexpr static std::size_t size() { return 1; }
};
static_assert( std::ranges::forward_range<EmptyTinyView>);
static_assert( std::ranges::__tiny_range<EmptyTinyView>);
static_assert( std::ranges::view<EmptyTinyView>);
static_assert(sizeof(std::ranges::lazy_split_view<EmptyInputView, EmptyTinyView>) ==
sizeof(std::ranges::__non_propagating_cache<std::ranges::iterator_t<EmptyInputView>>));
} // namespace test4