diff --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h --- a/libcxx/include/__ranges/subrange.h +++ b/libcxx/include/__ranges/subrange.h @@ -67,62 +67,41 @@ enum class _LIBCPP_ENUM_VIS subrange_kind : bool { unsized, sized }; - template - struct __subrange_base { - static constexpr bool __store_size = false; - _Iter __begin_ = _Iter(); - _Sent __end_ = _Sent(); - - _LIBCPP_HIDE_FROM_ABI - constexpr __subrange_base() = default; - - _LIBCPP_HIDE_FROM_ABI - constexpr __subrange_base(_Iter __iter, _Sent __sent, make_unsigned_t> = 0) - : __begin_(_VSTD::move(__iter)), __end_(__sent) { } - }; - - template - struct __subrange_base<_Iter, _Sent, true> { - static constexpr bool __store_size = true; - _Iter __begin_ = _Iter(); - _Sent __end_ = _Sent(); - make_unsigned_t> __size_ = 0; - - _LIBCPP_HIDE_FROM_ABI - constexpr __subrange_base() = default; - - _LIBCPP_HIDE_FROM_ABI - constexpr __subrange_base(_Iter __iter, _Sent __sent, decltype(__size_) __size) - : __begin_(_VSTD::move(__iter)), __end_(__sent), __size_(__size) { } - }; - template _Sent = _Iter, subrange_kind _Kind = sized_sentinel_for<_Sent, _Iter> ? subrange_kind::sized : subrange_kind::unsized> requires (_Kind == subrange_kind::sized || !sized_sentinel_for<_Sent, _Iter>) - struct _LIBCPP_TEMPLATE_VIS subrange - : public view_interface>, - private __subrange_base<_Iter, _Sent, _Kind == subrange_kind::sized && !sized_sentinel_for<_Sent, _Iter>> { - - using _Base = __subrange_base<_Iter, _Sent, _Kind == subrange_kind::sized && !sized_sentinel_for<_Sent, _Iter>>; - + class _LIBCPP_TEMPLATE_VIS subrange + : public view_interface> + { + private: + static constexpr bool _StoreSize = (_Kind == subrange_kind::sized && !sized_sentinel_for<_Sent, _Iter>); + static constexpr bool _MustProvideSizeAtConstruction = !_StoreSize; // just to improve compiler diagnostics + struct _Empty { constexpr _Empty(auto) noexcept { } }; + using _Size = conditional_t<_StoreSize, make_unsigned_t>, _Empty>; + [[no_unique_address]] _Iter __begin_ = _Iter(); + [[no_unique_address]] _Sent __end_ = _Sent(); + [[no_unique_address]] _Size __size_ = 0; + + public: _LIBCPP_HIDE_FROM_ABI subrange() requires default_initializable<_Iter> = default; _LIBCPP_HIDE_FROM_ABI constexpr subrange(__convertible_to_non_slicing<_Iter> auto __iter, _Sent __sent) - requires (!_Base::__store_size) - : _Base(_VSTD::move(__iter), __sent) {} + requires _MustProvideSizeAtConstruction + : __begin_(_VSTD::move(__iter)), __end_(std::move(__sent)) + { } _LIBCPP_HIDE_FROM_ABI constexpr subrange(__convertible_to_non_slicing<_Iter> auto __iter, _Sent __sent, make_unsigned_t> __n) requires (_Kind == subrange_kind::sized) - : _Base(_VSTD::move(__iter), __sent, __n) + : __begin_(_VSTD::move(__iter)), __end_(std::move(__sent)), __size_(__n) { if constexpr (sized_sentinel_for<_Sent, _Iter>) - _LIBCPP_ASSERT((this->__end_ - this->__begin_) == static_cast>(__n), + _LIBCPP_ASSERT((__end_ - __begin_) == static_cast>(__n), "std::ranges::subrange was passed an invalid size hint"); } @@ -132,8 +111,9 @@ convertible_to, _Sent> _LIBCPP_HIDE_FROM_ABI constexpr subrange(_Range&& __range) - requires (!_Base::__store_size) - : subrange(ranges::begin(__range), ranges::end(__range)) { } + requires (!_StoreSize) + : subrange(ranges::begin(__range), ranges::end(__range)) + { } template<__different_from _Range> requires borrowed_range<_Range> && @@ -141,9 +121,9 @@ convertible_to, _Sent> _LIBCPP_HIDE_FROM_ABI constexpr subrange(_Range&& __range) - requires _Base::__store_size && sized_range<_Range> - : subrange(__range, ranges::size(__range)) { } - + requires _StoreSize && sized_range<_Range> + : subrange(__range, ranges::size(__range)) + { } template requires __convertible_to_non_slicing, _Iter> && @@ -151,39 +131,47 @@ _LIBCPP_HIDE_FROM_ABI constexpr subrange(_Range&& __range, make_unsigned_t> __n) requires (_Kind == subrange_kind::sized) - : subrange(ranges::begin(__range), ranges::end(__range), __n) { } + : subrange(ranges::begin(__range), ranges::end(__range), __n) + { } template<__different_from _Pair> requires __pair_like_convertible_from<_Pair, const _Iter&, const _Sent&> _LIBCPP_HIDE_FROM_ABI - constexpr operator _Pair() const { return _Pair(this->__begin_, this->__end_); } + constexpr operator _Pair() const { + return _Pair(__begin_, __end_); + } _LIBCPP_HIDE_FROM_ABI constexpr _Iter begin() const requires copyable<_Iter> { - return this->__begin_; + return __begin_; } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Iter begin() requires (!copyable<_Iter>) { - return _VSTD::move(this->__begin_); + return _VSTD::move(__begin_); } _LIBCPP_HIDE_FROM_ABI - constexpr _Sent end() const { return this->__end_; } + constexpr _Sent end() const { + return __end_; + } - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const { return this->__begin_ == this->__end_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const { + return __begin_ == __end_; + } _LIBCPP_HIDE_FROM_ABI constexpr make_unsigned_t> size() const requires (_Kind == subrange_kind::sized) { - if constexpr (_Base::__store_size) - return this->__size_; + if constexpr (_StoreSize) + return __size_; else - return __to_unsigned_like(this->__end_ - this->__begin_); + return _VSTD::__to_unsigned_like(__end_ - __begin_); } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange next(iter_difference_t<_Iter> __n = 1) const& - requires forward_iterator<_Iter> { + requires forward_iterator<_Iter> + { auto __tmp = *this; __tmp.advance(__n); return __tmp; @@ -195,7 +183,8 @@ } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange prev(iter_difference_t<_Iter> __n = 1) const - requires bidirectional_iterator<_Iter> { + requires bidirectional_iterator<_Iter> + { auto __tmp = *this; __tmp.advance(-__n); return __tmp; @@ -205,16 +194,16 @@ constexpr subrange& advance(iter_difference_t<_Iter> __n) { if constexpr (bidirectional_iterator<_Iter>) { if (__n < 0) { - ranges::advance(this->__begin_, __n); - if constexpr (_Base::__store_size) - this->__size_ += _VSTD::__to_unsigned_like(-__n); + ranges::advance(__begin_, __n); + if constexpr (_StoreSize) + __size_ += _VSTD::__to_unsigned_like(-__n); return *this; } } - auto __d = __n - ranges::advance(this->__begin_, __n, this->__end_); - if constexpr (_Base::__store_size) - this->__size_ -= _VSTD::__to_unsigned_like(__d); + auto __d = __n - ranges::advance(__begin_, __n, __end_); + if constexpr (_StoreSize) + __size_ -= _VSTD::__to_unsigned_like(__d); return *this; } }; diff --git a/libcxx/test/std/ranges/range.utility/range.subrange/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.utility/range.subrange/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.subrange/ctor.default.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr subrange() requires default_initializable; + +#include + +#include +#include + +#include "test_iterators.h" + +// An input_or_output_iterator that is not default constructible so we can test +// the `requires` on subrange's default constructor. +struct NoDefaultIterator { + using difference_type = std::ptrdiff_t; + NoDefaultIterator() = delete; + NoDefaultIterator& operator++(); + void operator++(int); + int& operator*() const; + friend bool operator==(NoDefaultIterator const&, NoDefaultIterator const&); +}; +static_assert(std::input_or_output_iterator); + +// A sentinel type for the above iterator +struct Sentinel { + friend bool operator==(NoDefaultIterator const&, Sentinel const&); + friend bool operator==(Sentinel const&, NoDefaultIterator const&); + friend bool operator!=(NoDefaultIterator const&, Sentinel const&); + friend bool operator!=(Sentinel const&, NoDefaultIterator const&); +}; + +constexpr bool test() { + { + static_assert(!std::is_default_constructible_v>); + static_assert(!std::is_default_constructible_v>); + } + + { + using Iter = forward_iterator; + std::ranges::subrange subrange; + assert(subrange.begin() == Iter()); + assert(subrange.end() == Iter()); + } + { + using Iter = forward_iterator; + std::ranges::subrange subrange; + assert(subrange.begin() == Iter()); + assert(subrange.end() == Iter()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}