diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -144,6 +144,7 @@ ratio ranges __ranges/access.h + __ranges/concepts.h regex scoped_allocator semaphore diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/concepts.h @@ -0,0 +1,61 @@ +// -*- C++ -*- +//===-------------------------- concepts ----------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP_RANGES_CONCEPTS_H +#define _LIBCPP_RANGES_CONCEPTS_H + +#include <__config> +#include <__ranges/access.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { +// [range.range] +template +concept range = requires(_Tp& __t) { + ranges::begin(__t); // sometimes equality-preserving + ranges::end(__t); +}; + +// `iterator_t` is repeated in <__ranges/access.h> and <__ranges/concepts.h> for clarity's sake. +template +using iterator_t = decltype(ranges::begin(declval<_Tp&>())); + +template +using sentinel_t = decltype(ranges::end(declval<_Rp&>())); + +template +using range_difference_t = iter_difference_t >; + +template +using range_value_t = iter_value_t >; + +template +using range_reference_t = iter_reference_t >; + +template +using range_rvalue_reference_t = iter_rvalue_reference_t >; +} // namespace ranges + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_RANGES_CONCEPTS_H diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -22,7 +22,22 @@ // // // [range.range], ranges // template +// concept range = see below; +// +// template +// using iterator_t = decltype(ranges::begin(declval())); +// template // using iterator_t = decltype(ranges::begin(declval())); +// template +// using sentinel_t = decltype(ranges::end(declval())); +// template +// using range_difference_t = iter_difference_t>; +// template +// using range_value_t = iter_value_t>; +// template +// using range_reference_t = iter_reference_t>; +// template +// using range_rvalue_reference_t = iter_rvalue_reference_t>; // } #ifndef _LIBCPP_RANGES @@ -33,5 +48,6 @@ #include // see [iterator.synopsis] #include <__ranges/access.h> +#include <__ranges/concepts.h> #endif // _LIBCPP_RANGES diff --git a/libcxx/test/std/ranges/range.range/helper_aliases.compile.pass.cpp b/libcxx/test/std/ranges/range.range/helper_aliases.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.range/helper_aliases.compile.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc-10 + +// template +// using range_difference_t = iter_difference_t>; + +// template +// using range_value_t = iter_value_t>; + +// template +// using range_reference_t = iter_reference_t>; + +// template +// using range_rvalue_reference_t = iter_rvalue_reference_t>; + +#include + +#include +#include +#include + +#include "test_range.h" + +namespace stdr = std::ranges; + +static_assert(std::same_as >, + std::iter_difference_t > > >); +static_assert(std::same_as > >, + std::iter_difference_t > > >); + +static_assert( + std::same_as >, std::iter_value_t > > >); +static_assert(std::same_as > >, + std::iter_value_t > > >); + +static_assert(std::same_as >, + std::iter_reference_t > > >); +static_assert(std::same_as > >, + std::iter_reference_t > > >); + +static_assert(std::same_as >, + std::iter_rvalue_reference_t > > >); +static_assert(std::same_as > >, + std::iter_rvalue_reference_t > > >); diff --git a/libcxx/test/std/ranges/range.range/range.compile.pass.cpp b/libcxx/test/std/ranges/range.range/range.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.range/range.compile.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc-10 + +// template +// concept range; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_range.h" + +namespace stdr = std::ranges; + +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range); +static_assert(stdr::range); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range >); + +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range >); +static_assert(stdr::range >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); +static_assert(stdr::range > >); + +struct incompatible_iterators { + std::vector::iterator begin(); + std::deque::iterator end(); +}; +static_assert(!stdr::range); + +struct int_begin_int_end { + int begin(); + int end(); +}; +static_assert(!stdr::range); + +struct iterator_begin_int_end { + std::vector::iterator begin(); + int end(); +}; +static_assert(!stdr::range); + +struct int_begin_iterator_end { + int begin(); + std::vector::iterator end(); +}; +static_assert(!stdr::range); diff --git a/libcxx/test/std/ranges/range.range/sentinel_t.compile.pass.cpp b/libcxx/test/std/ranges/range.range/sentinel_t.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.range/sentinel_t.compile.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc-10 + +// template +// using sentinel_t = decltype(ranges::end(declval<_Rp&>())); + +#include + +#include +#include +#include +#include +#include +#include + +#include "test_range.h" + +namespace stdr = std::ranges; + +static_assert(std::same_as >, std::forward_list::iterator>); +static_assert(std::same_as const>, std::forward_list::const_iterator>); + +static_assert(std::same_as >, std::deque::iterator>); +static_assert(std::same_as const>, std::deque::const_iterator>); + +static_assert(std::same_as >, std::list::iterator>); +static_assert(std::same_as const>, std::list::const_iterator>); + +static_assert(std::same_as >, std::vector::iterator>); +static_assert(std::same_as const>, std::vector::const_iterator>); + +static_assert(std::same_as > >, sentinel>); +static_assert(std::same_as const> >, sentinel>); + +static_assert(std::same_as > >, sentinel>); +static_assert(std::same_as const> >, sentinel>); + +static_assert(std::same_as > >, sentinel>); +static_assert(std::same_as const> >, sentinel>); + +static_assert(std::same_as > >, sentinel>); +static_assert(std::same_as const> >, sentinel>); diff --git a/libcxx/test/support/test_range.h b/libcxx/test/support/test_range.h new file mode 100644 --- /dev/null +++ b/libcxx/test/support/test_range.h @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef LIBCXX_TEST_SUPPORT_TEST_RANGE_H +#define LIBCXX_TEST_SUPPORT_TEST_RANGE_H + +#include + +#ifdef _LIBCPP_HAS_NO_RANGES +#error "test/suppoort/test_range.h" can only be included in builds supporting ranges +#endif + +struct sentinel { + bool operator==(std::input_or_output_iterator auto) const; +}; + +template +struct range { + std::ranges::iterator_t begin(); + std::ranges::iterator_t begin() const; + sentinel end(); + sentinel end() const; +}; + +#endif // LIBCXX_TEST_SUPPORT_TEST_RANGE_H