diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -135,7 +135,7 @@ "","","","","","" "`P0883 <https://wg21.link/P0883>`__","LWG","Fixing Atomic Initialization","Belfast","|Complete| [#note-P0883]_","13.0" "`P1391 <https://wg21.link/P1391>`__","LWG","Range constructor for std::string_view","Belfast","* *","" -"`P1394 <https://wg21.link/P1394>`__","LWG","Range constructor for std::span","Belfast","* *","" +"`P1394 <https://wg21.link/P1394>`__","LWG","Range constructor for std::span","Belfast","|Complete|","14.0" "`P1456 <https://wg21.link/P1456>`__","LWG","Move-only views","Belfast","* *","" "`P1622 <https://wg21.link/P1622>`__","LWG","Mandating the Standard Library: Clause 32 - Thread support library","Belfast","* *","" "`P1645 <https://wg21.link/P1645>`__","LWG","constexpr for numeric algorithms","Belfast","|Complete|","12.0" diff --git a/libcxx/include/span b/libcxx/include/span --- a/libcxx/include/span +++ b/libcxx/include/span @@ -56,18 +56,18 @@ // [span.cons], span constructors, copy, assignment, and destructor constexpr span() noexcept; - constexpr explicit(Extent != dynamic_extent) span(pointer ptr, size_type count); - constexpr explicit(Extent != dynamic_extent) span(pointer firstElem, pointer lastElem); + template <class It> + constexpr explicit(Extent != dynamic_extent) span(It first, size_type count); + template <class It, class End> + constexpr explicit(Extent != dynamic_extent) span(It first, End last); template <size_t N> constexpr span(element_type (&arr)[N]) noexcept; template <size_t N> constexpr span(array<value_type, N>& arr) noexcept; template <size_t N> constexpr span(const array<value_type, N>& arr) noexcept; - template <class Container> - constexpr explicit(Extent != dynamic_extent) span(Container& cont); - template <class Container> - constexpr explicit(Extent != dynamic_extent) span(const Container& cont); + template<class R> + constexpr explicit(extent != dynamic_extent) span(R&& r); constexpr span(const span& other) noexcept = default; template <class OtherElementType, size_t OtherExtent> constexpr explicit(Extent != dynamic_extent) span(const span<OtherElementType, OtherExtent>& s) noexcept; @@ -108,6 +108,9 @@ size_type size_; // exposition only }; +template<class It, class EndOrSize> + span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<_It>>>; + template<class T, size_t N> span(T (&)[N]) -> span<T, N>; @@ -117,11 +120,8 @@ template<class T, size_t N> span(const array<T, N>&) -> span<const T, N>; -template<class Container> - span(Container&) -> span<typename Container::value_type>; - -template<class Container> - span(const Container&) -> span<const typename Container::value_type>; +template<class R> + span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>; } // namespace std @@ -129,7 +129,10 @@ #include <__config> #include <__debug> +#include <__iterator/concepts.h> #include <__iterator/wrap_iter.h> +#include <__ranges/concepts.h> +#include <__ranges/data.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> #include <array> // for array @@ -155,22 +158,16 @@ template <class _Tp> -struct __is_span_impl : public false_type {}; +struct __is_std_array : false_type {}; -template <class _Tp, size_t _Extent> -struct __is_span_impl<span<_Tp, _Extent>> : public true_type {}; - -template <class _Tp> -struct __is_span : public __is_span_impl<remove_cv_t<_Tp>> {}; +template <class _Tp, size_t _Sz> +struct __is_std_array<array<_Tp, _Sz>> : true_type {}; template <class _Tp> -struct __is_std_array_impl : public false_type {}; +struct __is_std_span : false_type {}; template <class _Tp, size_t _Sz> -struct __is_std_array_impl<array<_Tp, _Sz>> : public true_type {}; - -template <class _Tp> -struct __is_std_array : public __is_std_array_impl<remove_cv_t<_Tp>> {}; +struct __is_std_span<span<_Tp, _Sz>> : true_type {}; template <class _Tp, class _ElementType, class = void> struct __is_span_compatible_container : public false_type {}; @@ -179,9 +176,9 @@ struct __is_span_compatible_container<_Tp, _ElementType, void_t< // is not a specialization of span - enable_if_t<!__is_span<_Tp>::value, nullptr_t>, + enable_if_t<!__is_std_span<remove_cvref_t<_Tp>>::value, nullptr_t>, // is not a specialization of array - enable_if_t<!__is_std_array<_Tp>::value, nullptr_t>, + enable_if_t<!__is_std_array<remove_cvref_t<_Tp>>::value, nullptr_t>, // is_array_v<Container> is false, enable_if_t<!is_array_v<_Tp>, nullptr_t>, // data(cont) and size(cont) are well formed @@ -195,6 +192,17 @@ >> : public true_type {}; +#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_RANGES) +template <class _Range, class _ElementType> +concept __is_span_compatible_range = + ranges::contiguous_range<_Range> && + ranges::sized_range<_Range> && + (ranges::borrowed_range<_Range> || is_const_v<_ElementType>) && + !__is_std_span<remove_cvref_t<_Range>>::value && + !__is_std_array<remove_cvref_t<_Range>>::value && + !is_array_v<remove_cvref_t<_Range>> && + is_convertible_v<remove_reference_t<ranges::range_reference_t<_Range>> (*)[], _ElementType(*)[]>; +#endif template <typename _Tp, size_t _Extent> class _LIBCPP_TEMPLATE_VIS span { @@ -224,10 +232,25 @@ constexpr span (const span&) noexcept = default; constexpr span& operator=(const span&) noexcept = default; - _LIBCPP_INLINE_VISIBILITY constexpr explicit span(pointer __ptr, size_type __count) : __data{__ptr} - { (void)__count; _LIBCPP_ASSERT(_Extent == __count, "size mismatch in span's constructor (ptr, len)"); } - _LIBCPP_INLINE_VISIBILITY constexpr explicit span(pointer __f, pointer __l) : __data{__f} - { (void)__l; _LIBCPP_ASSERT(_Extent == distance(__f, __l), "size mismatch in span's constructor (ptr, ptr)"); } + template <class _It, enable_if_t<contiguous_iterator<_It> && + is_convertible_v<remove_reference_t<iter_reference_t<_It>>(*)[], element_type (*)[]>, nullptr_t> = nullptr> + _LIBCPP_INLINE_VISIBILITY constexpr explicit span(_It __first, size_type __count) : __data{_VSTD::to_address(__first)} + { + (void)__count; + _LIBCPP_ASSERT(_Extent == __count, "size mismatch in span's constructor (iterator, len)"); + } + + template <class _It, class _End, enable_if_t< + is_convertible_v<remove_reference_t<iter_reference_t<_It>>(*)[], element_type (*)[]> && + contiguous_iterator<_It> && + sized_sentinel_for<_End, _It> && + !is_convertible_v<_End, size_t>, nullptr_t> = nullptr> + _LIBCPP_INLINE_VISIBILITY constexpr explicit span(_It __first, _End __last) : __data{_VSTD::to_address(__first)} + { + (void) __last; + _LIBCPP_ASSERT(__first <= __last, "invalid range in span's constructor (iterator, sentinel)"); + _LIBCPP_ASSERT(last - first == _Extent, "invalid range in span's constructor (iterator sentinel): last - first != extent"); + } _LIBCPP_INLINE_VISIBILITY constexpr span(element_type (&__arr)[_Extent]) noexcept : __data{__arr} {} @@ -241,21 +264,12 @@ _LIBCPP_INLINE_VISIBILITY constexpr span(const array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {} - template <class _Container> - _LIBCPP_INLINE_VISIBILITY - constexpr explicit span( _Container& __c, - enable_if_t<__is_span_compatible_container<_Container, _Tp>::value, nullptr_t> = nullptr) - : __data{_VSTD::data(__c)} { - _LIBCPP_ASSERT(_Extent == _VSTD::size(__c), "size mismatch in span's constructor (range)"); - } - - template <class _Container> - _LIBCPP_INLINE_VISIBILITY - constexpr explicit span(const _Container& __c, - enable_if_t<__is_span_compatible_container<const _Container, _Tp>::value, nullptr_t> = nullptr) - : __data{_VSTD::data(__c)} { - _LIBCPP_ASSERT(_Extent == _VSTD::size(__c), "size mismatch in span's constructor (range)"); - } +#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_RANGES) + template <__is_span_compatible_range<element_type> _Range> + _LIBCPP_INLINE_VISIBILITY constexpr explicit span(_Range&& __r) : __data{ranges::data(__r)} { + _LIBCPP_ASSERT(ranges::size(__r) == _Extent, "size mismatch in span's constructor (range)"); + } +#endif template <class _OtherElementType> _LIBCPP_INLINE_VISIBILITY @@ -402,8 +416,17 @@ constexpr span (const span&) noexcept = default; constexpr span& operator=(const span&) noexcept = default; - _LIBCPP_INLINE_VISIBILITY constexpr span(pointer __ptr, size_type __count) : __data{__ptr}, __size{__count} {} - _LIBCPP_INLINE_VISIBILITY constexpr span(pointer __f, pointer __l) : __data{__f}, __size{static_cast<size_t>(distance(__f, __l))} {} + template <class _It, enable_if_t<contiguous_iterator<_It> && + is_convertible_v<remove_reference_t<iter_reference_t<_It>>(*)[], element_type (*)[]>, nullptr_t> = nullptr> + _LIBCPP_INLINE_VISIBILITY constexpr span(_It __first, size_type __count) : __data{_VSTD::to_address(__first)}, __size{__count} {} + + template <class _It, class _End, enable_if_t< + is_convertible_v<remove_reference_t<iter_reference_t<_It>>(*)[], element_type (*)[]> && + contiguous_iterator<_It> && + sized_sentinel_for<_End, _It> && + !is_convertible_v<_End, size_t>, nullptr_t> = nullptr> + _LIBCPP_INLINE_VISIBILITY constexpr span(_It __first, _End __last) + : __data{_VSTD::to_address(__first)}, __size(static_cast<size_t>(_VSTD::distance(__first, __last))) {} template <size_t _Sz> _LIBCPP_INLINE_VISIBILITY @@ -419,18 +442,11 @@ _LIBCPP_INLINE_VISIBILITY constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} - template <class _Container> - _LIBCPP_INLINE_VISIBILITY - constexpr span( _Container& __c, - enable_if_t<__is_span_compatible_container<_Container, _Tp>::value, nullptr_t> = nullptr) - : __data{_VSTD::data(__c)}, __size{(size_type) _VSTD::size(__c)} {} - - template <class _Container> - _LIBCPP_INLINE_VISIBILITY - constexpr span(const _Container& __c, - enable_if_t<__is_span_compatible_container<const _Container, _Tp>::value, nullptr_t> = nullptr) - : __data{_VSTD::data(__c)}, __size{(size_type) _VSTD::size(__c)} {} - +#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_RANGES) + template <__is_span_compatible_range<element_type> _Range> + _LIBCPP_INLINE_VISIBILITY constexpr explicit span(_Range&& __r) : __data{ranges::data(__r)}, __size{ranges::size(__r)} { + } +#endif template <class _OtherElementType, size_t _OtherExtent> _LIBCPP_INLINE_VISIBILITY @@ -557,6 +573,9 @@ { return __s.__as_writable_bytes(); } // Deduction guides +template<contiguous_iterator _It, class _EndOrSize> + span(_It, _EndOrSize) -> span<remove_reference_t<iter_reference_t<_It>>>; + template<class _Tp, size_t _Sz> span(_Tp (&)[_Sz]) -> span<_Tp, _Sz>; @@ -566,11 +585,10 @@ template<class _Tp, size_t _Sz> span(const array<_Tp, _Sz>&) -> span<const _Tp, _Sz>; -template<class _Container> - span(_Container&) -> span<typename _Container::value_type>; - -template<class _Container> - span(const _Container&) -> span<const typename _Container::value_type>; +#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_RANGES) +template<ranges::contiguous_range _Range> + span(_Range&&) -> span<remove_reference_t<ranges::range_reference_t<_Range>>>; +#endif #endif // _LIBCPP_STD_VER > 17 diff --git a/libcxx/test/std/containers/views/span.cons/container.fail.cpp b/libcxx/test/std/containers/views/span.cons/container.fail.cpp deleted file mode 100644 --- a/libcxx/test/std/containers/views/span.cons/container.fail.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// -*- C++ -*- -//===------------------------------ span ---------------------------------===// -// -// 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 - -// <span> - -// template<class Container> -// constexpr span(Container& cont); -// template<class Container> -// constexpr span(const Container& cont); -// -// Remarks: These constructors shall not participate in overload resolution unless: -// — extent == dynamic_extent, -// — Container is not a specialization of span, -// — Container is not a specialization of array, -// — is_array_v<Container> is false, -// — data(cont) and size(cont) are both well-formed, and -// — remove_pointer_t<decltype(data(cont))>(*)[] is convertible to ElementType(*)[]. -// - -#include <span> -#include <cassert> -#include <deque> -#include <forward_list> -#include <list> -#include <vector> - -#include "test_macros.h" - -// Look ma - I'm a container! -template <typename T> -struct IsAContainer { - constexpr IsAContainer() : v_{} {} - constexpr size_t size() const {return 1;} - constexpr T *data() {return &v_;} - constexpr const T *data() const {return &v_;} - - constexpr const T *getV() const {return &v_;} // for checking - T v_; -}; - -template <typename T> -struct NotAContainerNoData { - size_t size() const {return 0;} -}; - -template <typename T> -struct NotAContainerNoSize { - const T *data() const {return nullptr;} -}; - -template <typename T> -struct NotAContainerPrivate { -private: - size_t size() const {return 0;} - const T *data() const {return nullptr;} -}; - -template<class T, size_t extent, class container> -std::span<T, extent> createImplicitSpan(container c) { - return {c}; // expected-error {{chosen constructor is explicit in copy-initialization}} -} - -int main(int, char**) -{ - -// Making non-const spans from const sources (a temporary binds to `const &`) - { - std::span<int> s1{IsAContainer<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span<int> s3{std::vector<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - } - -// Missing size and/or data - { - std::span<const int> s1{NotAContainerNoData<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span<const int> s3{NotAContainerNoSize<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span<const int> s5{NotAContainerPrivate<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - -// Again with the standard containers - std::span<const int> s11{std::deque<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span<const int> s13{std::list<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span<const int> s15{std::forward_list<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - } - -// Not the same type - { - IsAContainer<int> c; - std::span<float> s1{c}; // expected-error {{no matching constructor for initialization of 'std::span<float>'}} - } - -// CV wrong - { - IsAContainer<const int> c; - IsAContainer<const volatile int> cv; - IsAContainer< volatile int> v; - - std::span< int> s1{c}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span< int> s2{v}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span< int> s3{cv}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span<const int> s4{v}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span<const int> s5{cv}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span< volatile int> s6{c}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} - std::span< volatile int> s7{cv}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} - } - -// explicit constructor necessary - { - IsAContainer<int> c; - const IsAContainer<int> cc; - - createImplicitSpan<int, 1>(c); - createImplicitSpan<int, 1>(cc); - } - - return 0; -} diff --git a/libcxx/test/std/containers/views/span.cons/container.pass.cpp b/libcxx/test/std/containers/views/span.cons/container.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/containers/views/span.cons/container.pass.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// -*- C++ -*- -//===------------------------------ span ---------------------------------===// -// -// 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 - -// <span> - -// template<class Container> -// constexpr span(Container& cont); -// template<class Container> -// constexpr span(const Container& cont); -// -// Remarks: These constructors shall not participate in overload resolution unless: -// — extent == dynamic_extent, -// — Container is not a specialization of span, -// — Container is not a specialization of array, -// — is_array_v<Container> is false, -// — data(cont) and size(cont) are both well-formed, and -// — remove_pointer_t<decltype(data(cont))>(*)[] is convertible to ElementType(*)[]. -// - - -#include <span> -#include <cassert> -#include <string> -#include <vector> - -#include "test_macros.h" - -// Look ma - I'm a container! -template <typename T> -struct IsAContainer { - constexpr IsAContainer() : v_{} {} - constexpr size_t size() const {return 1;} - constexpr T *data() {return &v_;} - constexpr const T *data() const {return &v_;} - constexpr T *begin() {return &v_;} - constexpr const T *begin() const {return &v_;} - constexpr T *end() {return &v_ + 1;} - constexpr const T *end() const {return &v_ + 1;} - - constexpr T const *getV() const {return &v_;} // for checking - T v_; -}; - - -void checkCV() -{ - std::vector<int> v = {1,2,3}; - -// Types the same - { - std::span< int> s1{v}; // a span< int> pointing at int. - } - -// types different - { - std::span<const int> s1{v}; // a span<const int> pointing at int. - std::span< volatile int> s2{v}; // a span< volatile int> pointing at int. - std::span< volatile int> s3{v}; // a span< volatile int> pointing at const int. - std::span<const volatile int> s4{v}; // a span<const volatile int> pointing at int. - } - -// Constructing a const view from a temporary - { - std::span<const int> s1{IsAContainer<int>()}; - std::span<const int> s3{std::vector<int>()}; - (void) s1; - (void) s3; - } -} - - -template <typename T> -constexpr bool testConstexprSpan() -{ - constexpr IsAContainer<const T> val{}; - std::span<const T> s1{val}; - return s1.data() == val.getV() && s1.size() == 1; -} - -template <typename T> -constexpr bool testConstexprSpanStatic() -{ - constexpr IsAContainer<const T> val{}; - std::span<const T, 1> s1{val}; - return s1.data() == val.getV() && s1.size() == 1; -} - -template <typename T> -void testRuntimeSpan() -{ - IsAContainer<T> val{}; - const IsAContainer<T> cVal; - std::span<T> s1{val}; - std::span<const T> s2{cVal}; - assert(s1.data() == val.getV() && s1.size() == 1); - assert(s2.data() == cVal.getV() && s2.size() == 1); -} - -template <typename T> -void testRuntimeSpanStatic() -{ - IsAContainer<T> val{}; - const IsAContainer<T> cVal; - std::span<T, 1> s1{val}; - std::span<const T, 1> s2{cVal}; - assert(s1.data() == val.getV() && s1.size() == 1); - assert(s2.data() == cVal.getV() && s2.size() == 1); -} - -struct A{}; - -int main(int, char**) -{ - static_assert(testConstexprSpan<int>(), ""); - static_assert(testConstexprSpan<long>(), ""); - static_assert(testConstexprSpan<double>(), ""); - static_assert(testConstexprSpan<A>(), ""); - - static_assert(testConstexprSpanStatic<int>(), ""); - static_assert(testConstexprSpanStatic<long>(), ""); - static_assert(testConstexprSpanStatic<double>(), ""); - static_assert(testConstexprSpanStatic<A>(), ""); - - testRuntimeSpan<int>(); - testRuntimeSpan<long>(); - testRuntimeSpan<double>(); - testRuntimeSpan<std::string>(); - testRuntimeSpan<A>(); - - testRuntimeSpanStatic<int>(); - testRuntimeSpanStatic<long>(); - testRuntimeSpanStatic<double>(); - testRuntimeSpanStatic<std::string>(); - testRuntimeSpanStatic<A>(); - - checkCV(); - - return 0; -} diff --git a/libcxx/test/std/containers/views/span.cons/deduct.pass.cpp b/libcxx/test/std/containers/views/span.cons/deduct.pass.cpp --- a/libcxx/test/std/containers/views/span.cons/deduct.pass.cpp +++ b/libcxx/test/std/containers/views/span.cons/deduct.pass.cpp @@ -1,4 +1,3 @@ -// -*- C++ -*- //===------------------------------ span ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -7,9 +6,13 @@ // //===---------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges // <span> +// template<class It, class EndOrSize> +// span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<_It>>>; +// // template<class T, size_t N> // span(T (&)[N]) -> span<T, N>; // @@ -19,12 +22,8 @@ // template<class T, size_t N> // span(const array<T, N>&) -> span<const T, N>; // -// template<class Container> -// span(Container&) -> span<typename Container::value_type>; -// -// template<class Container> -// span(const Container&) -> span<const typename Container::value_type>; - +// template<class R> +// span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>; #include <span> @@ -33,12 +32,28 @@ #include <memory> #include <string> +#include "simple_range.h" #include "test_macros.h" -int main(int, char**) -{ +void test_iterator_sentinel() { + int arr[] = {1, 2, 3}; + { + std::span s{std::begin(arr), std::end(arr)}; + ASSERT_SAME_TYPE(decltype(s), std::span<int>); + assert(s.size() == std::size(arr)); + assert(s.data() == std::data(arr)); + } + { + std::span s{std::begin(arr), 3}; + ASSERT_SAME_TYPE(decltype(s), std::span<int>); + assert(s.size() == std::size(arr)); + assert(s.data() == std::data(arr)); + } +} + +void test_c_array() { { - int arr[] = {1,2,3}; + int arr[] = {1, 2, 3}; std::span s{arr}; ASSERT_SAME_TYPE(decltype(s), std::span<int, 3>); assert(s.size() == std::size(arr)); @@ -52,7 +67,9 @@ assert(s.size() == std::size(arr)); assert(s.data() == std::data(arr)); } +} +void test_std_array() { { std::array<double, 4> arr = {1.0, 2.0, 3.0, 4.0}; std::span s{arr}; @@ -68,7 +85,9 @@ assert(s.size() == arr.size()); assert(s.data() == arr.data()); } +} +void test_range_std_container() { { std::string str{"ABCDE"}; std::span s{str}; @@ -84,6 +103,33 @@ assert(s.size() == str.size()); assert(s.data() == str.data()); } +} + +void test_range_user_defined() { + { + SimpleRange<int, 3> r{}; + std::span s{r}; + ASSERT_SAME_TYPE(decltype(s), std::span<int>); + assert(s.size() == r.size()); + assert(s.data() == r.data()); + } + + { + const SimpleRange<int, 3> r{}; + std::span s{r}; + ASSERT_SAME_TYPE(decltype(s), std::span<const int>); + assert(s.size() == r.size()); + assert(s.data() == r.data()); + } +} + +int main(int, char**) +{ + test_iterator_sentinel(); + test_c_array(); + test_std_array(); + test_range_std_container(); + test_range_user_defined(); return 0; } diff --git a/libcxx/test/std/containers/views/span.cons/iterator_iterator.compile.pass.cpp b/libcxx/test/std/containers/views/span.cons/iterator_iterator.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/span.cons/iterator_iterator.compile.pass.cpp @@ -0,0 +1,46 @@ +//===------------------------------ span ---------------------------------===// +// +// 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-has-no-incomplete-ranges + +// <span> + +// template <class It, class End> +// constexpr explicit(Extent != dynamic_extent) span(It first, End last); +// Requires: [first, last) shall be a valid range. +// If extent is not equal to dynamic_extent, then last - first shall be equal to extent. +// + +#include <span> + +#include <type_traits> + +template <size_t Extent> +void test_cv() { + static_assert( std::is_constructible_v<std::span<int, Extent>, int*, int*>); + static_assert(!std::is_constructible_v<std::span<int, Extent>, const int*, const int*>); + static_assert(!std::is_constructible_v<std::span<int, Extent>, volatile int*, volatile int*>); + static_assert( std::is_constructible_v<std::span<const int, Extent>, int*, int*>); + static_assert( std::is_constructible_v<std::span<const int, Extent>, const int*, const int*>); + static_assert(!std::is_constructible_v<std::span<const int, Extent>, volatile int*, volatile int*>); + static_assert( std::is_constructible_v<std::span<volatile int, Extent>, int*, int*>); + static_assert(!std::is_constructible_v<std::span<volatile int, Extent>, const int*, const int*>); + static_assert( std::is_constructible_v<std::span<volatile int, Extent>, volatile int*, volatile int*>); +} + +int main(int, char**) +{ + // Types wrong + static_assert(!std::is_constructible_v<std::span<int>, int*, float*>); + static_assert(!std::is_constructible_v<std::span<int, 3>, int*, float*>); + + test_cv<std::dynamic_extent>(); + test_cv<3>(); + + return 0; +} diff --git a/libcxx/test/std/containers/views/span.cons/iterator_iterator.fail.cpp b/libcxx/test/std/containers/views/span.cons/iterator_iterator.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/span.cons/iterator_iterator.fail.cpp @@ -0,0 +1,35 @@ +//===------------------------------ span ---------------------------------===// +// +// 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-has-no-incomplete-ranges + +// <span> + +// template <class It, class End> +// constexpr explicit(Extent != dynamic_extent) span(It first, End last); +// Requires: [first, last) shall be a valid range. +// If extent is not equal to dynamic_extent, then last - first shall be equal to extent. +// + +#include <span> + +template<class T, size_t extent> +std::span<T, extent> createImplicitSpan(T* first, T* last) { + return {first, last}; // expected-error {{chosen constructor is explicit in copy-initialization}} +} + +int main(int, char**) +{ + int arr[] = {1, 2, 3}; + // explicit constructor necessary + { + createImplicitSpan<int, 1>(std::begin(arr), std::next(std::begin(arr))); + } + + return 0; +} diff --git a/libcxx/test/std/containers/views/span.cons/iterator_iterator.pass.cpp b/libcxx/test/std/containers/views/span.cons/iterator_iterator.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/span.cons/iterator_iterator.pass.cpp @@ -0,0 +1,95 @@ +//===------------------------------ span ---------------------------------===// +// +// 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-has-no-incomplete-ranges + +// <span> + +// template <class It, class End> +// constexpr explicit(Extent != dynamic_extent) span(It first, End last); +// Requires: [first, last) shall be a valid range. +// If extent is not equal to dynamic_extent, then last - first shall be equal to extent. +// + +#include <span> +#include <cassert> + +void checkCV() +{ + int arr[] = {1,2,3}; + const int carr[] = {4,5,6}; + volatile int varr[] = {7,8,9}; + const volatile int cvarr[] = {1,3,5}; + +// Types the same (dynamic sized) + { + std::span< int> s1{std::begin(arr), std::end(arr)}; // a span< int> pointing at int. + std::span<const int> s2{std::begin(carr), std::end(carr)}; // a span<const int> pointing at const int. + std::span< volatile int> s3{std::begin(varr), std::end(varr)}; // a span< volatile int> pointing at volatile int. + std::span<const volatile int> s4{std::begin(cvarr), std::end(cvarr)}; // a span<const volatile int> pointing at const volatile int. + assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); + } + +// Types the same (static sized) + { + std::span< int,3> s1{std::begin(arr), std::end(arr)}; // a span< int> pointing at int. + std::span<const int,3> s2{std::begin(carr), std::end(carr)}; // a span<const int> pointing at const int. + std::span< volatile int,3> s3{std::begin(varr), std::end(varr)}; // a span< volatile int> pointing at volatile int. + std::span<const volatile int,3> s4{std::begin(cvarr), std::end(cvarr)}; // a span<const volatile int> pointing at const volatile int. + assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); + } + + +// Types different (dynamic sized) + { + std::span<const int> s1{std::begin(arr), std::end(arr)}; // a span<const int> pointing at int. + std::span< volatile int> s2{std::begin(arr), std::end(arr)}; // a span< volatile int> pointing at int. + std::span< volatile int> s3{std::begin(arr), std::end(arr)}; // a span< volatile int> pointing at const int. + std::span<const volatile int> s4{std::begin(arr), std::end(arr)}; // a span<const volatile int> pointing at int. + std::span<const volatile int> s5{std::begin(carr), std::end(carr)}; // a span<const volatile int> pointing at const int. + std::span<const volatile int> s6{std::begin(varr), std::end(varr)}; // a span<const volatile int> pointing at volatile int. + assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); + } + +// Types different (static sized) + { + std::span<const int,3> s1{std::begin(arr), std::end(arr)}; // a span<const int> pointing at int. + std::span< volatile int,3> s2{std::begin(arr), std::end(arr)}; // a span< volatile int> pointing at int. + std::span< volatile int,3> s3{std::begin(arr), std::end(arr)}; // a span< volatile int> pointing at const int. + std::span<const volatile int,3> s4{std::begin(arr), std::end(arr)}; // a span<const volatile int> pointing at int. + std::span<const volatile int,3> s5{std::begin(carr), std::cend(carr)}; // a span<const volatile int> pointing at const int. + std::span<const volatile int,3> s6{std::begin(varr), std::end(varr)}; // a span<const volatile int> pointing at volatile int. + assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); + } +} + +template <class T> +constexpr bool test() +{ + T val[2] = {}; + auto s1 = std::span<T>(std::begin(val), std::end(val)); + auto s2 = std::span<T, 2>(std::begin(val), std::end(val)); + assert(s1.data() == std::data(val) && s1.size() == std::size(val)); + assert(s2.data() == std::data(val) && s2.size() == std::size(val)); + return true; +} + +struct A{}; + +int main(int, char**) +{ + static_assert(test<int>()); + assert(test<int>()); + + static_assert(test<A>()); + assert(test<A>()); + + checkCV(); + + return 0; +} diff --git a/libcxx/test/std/containers/views/span.cons/iterator_len.fail.cpp b/libcxx/test/std/containers/views/span.cons/iterator_len.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/span.cons/iterator_len.fail.cpp @@ -0,0 +1,74 @@ +//===------------------------------ span ---------------------------------===// +// +// 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-has-no-incomplete-ranges + +// <span> + +// template <class It> +// constexpr explicit(Extent != dynamic_extent) span(It first, size_type count); +// If extent is not equal to dynamic_extent, then count shall be equal to extent. +// + +#include <span> +#include <cassert> +#include <string> + +#include "test_macros.h" + + + int arr[] = {1,2,3}; +const int carr[] = {4,5,6}; + volatile int varr[] = {7,8,9}; +const volatile int cvarr[] = {1,3,5}; + +template<class T, size_t extent> +std::span<T, extent> createImplicitSpan(T* ptr, size_t len) { + return {ptr, len}; // expected-error {{chosen constructor is explicit in copy-initialization}} +} + +int main(int, char**) +{ +// We can't check that the size doesn't match - because that's a runtime property +// std::span<int, 2> s1(arr, 3); + +// Type wrong + { + std::span<float> s1(std::begin(arr), 3); // expected-error {{no matching constructor for initialization of 'std::span<float>'}} + std::span<float, 3> s2(std::begin(arr), 3); // expected-error {{no matching constructor for initialization of 'std::span<float, 3>'}} + } + +// CV wrong (dynamically sized) + { + std::span< int> s1{std::begin(carr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} + std::span< int> s2{std::begin(varr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} + std::span< int> s3{std::begin(cvarr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} + std::span<const int> s4{std::begin(varr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} + std::span<const int> s5{std::begin(cvarr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} + std::span< volatile int> s6{std::begin(carr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} + std::span< volatile int> s7{std::begin(cvarr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} + } + +// CV wrong (statically sized) + { + std::span< int,3> s1{std::begin(carr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<int, 3>'}} + std::span< int,3> s2{std::begin(varr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<int, 3>'}} + std::span< int,3> s3{std::begin(cvarr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<int, 3>'}} + std::span<const int,3> s4{std::begin(varr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int, 3>'}} + std::span<const int,3> s5{std::begin(cvarr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int, 3>'}} + std::span< volatile int,3> s6{std::begin(carr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int, 3>'}} + std::span< volatile int,3> s7{std::begin(cvarr), 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int, 3>'}} + } + +// explicit constructor necessary + { + createImplicitSpan<int, 1>(arr, 1); + } + + return 0; +} diff --git a/libcxx/test/std/containers/views/span.cons/iterator_len.pass.cpp b/libcxx/test/std/containers/views/span.cons/iterator_len.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/span.cons/iterator_len.pass.cpp @@ -0,0 +1,98 @@ +//===------------------------------ span ---------------------------------===// +// +// 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-has-no-incomplete-ranges + +// <span> + +// template <class It> +// constexpr explicit(Extent != dynamic_extent) span(It first, size_type count); +// If extent is not equal to dynamic_extent, then count shall be equal to extent. +// + + +#include <span> +#include <cassert> + +#include "test_macros.h" + +void checkCV() +{ + int arr[] = {1,2,3}; + const int carr[] = {4,5,6}; + volatile int varr[] = {7,8,9}; + const volatile int cvarr[] = {1,3,5}; + +// Types the same (dynamic sized) + { + std::span< int> s1{std::begin(arr), 3}; // a span< int> pointing at int. + std::span<const int> s2{std::begin(carr), 3}; // a span<const int> pointing at const int. + std::span< volatile int> s3{std::begin(varr), 3}; // a span< volatile int> pointing at volatile int. + std::span<const volatile int> s4{std::begin(cvarr), 3}; // a span<const volatile int> pointing at const volatile int. + assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); + } + +// Types the same (static sized) + { + std::span< int,3> s1{std::begin(arr), 3}; // a span< int> pointing at int. + std::span<const int,3> s2{std::begin(carr), 3}; // a span<const int> pointing at const int. + std::span< volatile int,3> s3{std::begin(varr), 3}; // a span< volatile int> pointing at volatile int. + std::span<const volatile int,3> s4{std::begin(cvarr), 3}; // a span<const volatile int> pointing at const volatile int. + assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); + } + + +// types different (dynamic sized) + { + std::span<const int> s1{std::begin(arr), 3}; // a span<const int> pointing at int. + std::span< volatile int> s2{std::begin(arr), 3}; // a span< volatile int> pointing at int. + std::span< volatile int> s3{std::begin(arr), 3}; // a span< volatile int> pointing at const int. + std::span<const volatile int> s4{std::begin(arr), 3}; // a span<const volatile int> pointing at int. + std::span<const volatile int> s5{std::begin(carr), 3}; // a span<const volatile int> pointing at const int. + std::span<const volatile int> s6{std::begin(varr), 3}; // a span<const volatile int> pointing at volatile int. + assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); + } + +// types different (static sized) + { + std::span<const int,3> s1{std::begin(arr), 3}; // a span<const int> pointing at int. + std::span< volatile int,3> s2{std::begin(arr), 3}; // a span< volatile int> pointing at int. + std::span< volatile int,3> s3{std::begin(arr), 3}; // a span< volatile int> pointing at const int. + std::span<const volatile int,3> s4{std::begin(arr), 3}; // a span<const volatile int> pointing at int. + std::span<const volatile int,3> s5{std::begin(carr), 3}; // a span<const volatile int> pointing at const int. + std::span<const volatile int,3> s6{std::begin(varr), 3}; // a span<const volatile int> pointing at volatile int. + assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); + } +} + + +template <class T> +constexpr bool test() +{ + T val[2] = {}; + auto s1 = std::span<T>(val, 2); + auto s2 = std::span<T, 2>(val, 2); + assert(s1.data() == std::data(val) && s1.size() == std::size(val)); + assert(s2.data() == std::data(val) && s2.size() == std::size(val)); + return true; +} + +struct A{}; + +int main(int, char**) +{ + static_assert(test<int>()); + assert(test<int>()); + + static_assert(test<A>()); + assert(test<A>()); + + checkCV(); + + return 0; +} diff --git a/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp b/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp deleted file mode 100644 --- a/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -*- C++ -*- -//===------------------------------ span ---------------------------------===// -// -// 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 - -// <span> - -// constexpr span(pointer ptr, size_type count); -// Requires: [ptr, ptr + count) shall be a valid range. -// If extent is not equal to dynamic_extent, then count shall be equal to extent. -// - -#include <span> -#include <cassert> -#include <string> - -#include "test_macros.h" - - - int arr[] = {1,2,3}; -const int carr[] = {4,5,6}; - volatile int varr[] = {7,8,9}; -const volatile int cvarr[] = {1,3,5}; - -template<class T, size_t extent> -std::span<T, extent> createImplicitSpan(T* ptr, size_t len) { - return {ptr, len}; // expected-error {{chosen constructor is explicit in copy-initialization}} -} - -int main(int, char**) -{ -// We can't check that the size doesn't match - because that's a runtime property -// std::span<int, 2> s1(arr, 3); - -// Type wrong - { - std::span<float> s1(arr, 3); // expected-error {{no matching constructor for initialization of 'std::span<float>'}} - std::span<float, 3> s2(arr, 3); // expected-error {{no matching constructor for initialization of 'std::span<float, 3>'}} - } - -// CV wrong (dynamically sized) - { - std::span< int> s1{ carr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span< int> s2{ varr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span< int> s3{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span<const int> s4{ varr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span<const int> s5{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span< volatile int> s6{ carr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} - std::span< volatile int> s7{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} - } - -// CV wrong (statically sized) - { - std::span< int,3> s1{ carr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<int, 3>'}} - std::span< int,3> s2{ varr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<int, 3>'}} - std::span< int,3> s3{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<int, 3>'}} - std::span<const int,3> s4{ varr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int, 3>'}} - std::span<const int,3> s5{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int, 3>'}} - std::span< volatile int,3> s6{ carr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int, 3>'}} - std::span< volatile int,3> s7{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int, 3>'}} - } - -// explicit constructor necessary - { - createImplicitSpan<int, 1>(arr, 1); - } - - return 0; -} diff --git a/libcxx/test/std/containers/views/span.cons/ptr_len.pass.cpp b/libcxx/test/std/containers/views/span.cons/ptr_len.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/containers/views/span.cons/ptr_len.pass.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// -*- C++ -*- -//===------------------------------ span ---------------------------------===// -// -// 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 - -// <span> - -// constexpr span(pointer ptr, size_type count); -// Requires: [ptr, ptr + count) shall be a valid range. -// If extent is not equal to dynamic_extent, then count shall be equal to extent. -// - -#include <span> -#include <cassert> -#include <string> - -#include "test_macros.h" - -void checkCV() -{ - int arr[] = {1,2,3}; - const int carr[] = {4,5,6}; - volatile int varr[] = {7,8,9}; - const volatile int cvarr[] = {1,3,5}; - -// Types the same (dynamic sized) - { - std::span< int> s1{ arr, 3}; // a span< int> pointing at int. - std::span<const int> s2{ carr, 3}; // a span<const int> pointing at const int. - std::span< volatile int> s3{ varr, 3}; // a span< volatile int> pointing at volatile int. - std::span<const volatile int> s4{cvarr, 3}; // a span<const volatile int> pointing at const volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); - } - -// Types the same (static sized) - { - std::span< int,3> s1{ arr, 3}; // a span< int> pointing at int. - std::span<const int,3> s2{ carr, 3}; // a span<const int> pointing at const int. - std::span< volatile int,3> s3{ varr, 3}; // a span< volatile int> pointing at volatile int. - std::span<const volatile int,3> s4{cvarr, 3}; // a span<const volatile int> pointing at const volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); - } - - -// types different (dynamic sized) - { - std::span<const int> s1{ arr, 3}; // a span<const int> pointing at int. - std::span< volatile int> s2{ arr, 3}; // a span< volatile int> pointing at int. - std::span< volatile int> s3{ arr, 3}; // a span< volatile int> pointing at const int. - std::span<const volatile int> s4{ arr, 3}; // a span<const volatile int> pointing at int. - std::span<const volatile int> s5{carr, 3}; // a span<const volatile int> pointing at const int. - std::span<const volatile int> s6{varr, 3}; // a span<const volatile int> pointing at volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); - } - -// types different (static sized) - { - std::span<const int,3> s1{ arr, 3}; // a span<const int> pointing at int. - std::span< volatile int,3> s2{ arr, 3}; // a span< volatile int> pointing at int. - std::span< volatile int,3> s3{ arr, 3}; // a span< volatile int> pointing at const int. - std::span<const volatile int,3> s4{ arr, 3}; // a span<const volatile int> pointing at int. - std::span<const volatile int,3> s5{carr, 3}; // a span<const volatile int> pointing at const int. - std::span<const volatile int,3> s6{varr, 3}; // a span<const volatile int> pointing at volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); - } -} - - -template <typename T> -constexpr bool testConstexprSpan() -{ - constexpr T val[2] = {}; - std::span<const T> s1{val, 2}; - std::span<const T,2> s2{val, 2}; - return - s1.data() == &val[0] && s1.size() == 2 - && s2.data() == &val[0] && s2.size() == 2; -} - - -template <typename T> -void testRuntimeSpan() -{ - T val[2] = {}; - std::span<T> s1{val, 2}; - std::span<T,2> s2{val, 2}; - assert(s1.data() == &val[0] && s1.size() == 2); - assert(s2.data() == &val[0] && s2.size() == 2); -} - -struct A{}; - -int main(int, char**) -{ - static_assert(testConstexprSpan<int>(), ""); - static_assert(testConstexprSpan<long>(), ""); - static_assert(testConstexprSpan<double>(), ""); - static_assert(testConstexprSpan<A>(), ""); - - testRuntimeSpan<int>(); - testRuntimeSpan<long>(); - testRuntimeSpan<double>(); - testRuntimeSpan<std::string>(); - testRuntimeSpan<A>(); - - checkCV(); - - return 0; -} diff --git a/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp b/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp deleted file mode 100644 --- a/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -*- C++ -*- -//===------------------------------ span ---------------------------------===// -// -// 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 - -// <span> - -// constexpr span(pointer first, pointer last); -// Requires: [first, last) shall be a valid range. -// If extent is not equal to dynamic_extent, then last - first shall be equal to extent. -// - -#include <span> -#include <cassert> -#include <string> - -#include "test_macros.h" - - - int arr[] = {1,2,3}; -const int carr[] = {4,5,6}; - volatile int varr[] = {7,8,9}; -const volatile int cvarr[] = {1,3,5}; - -template<class T, size_t extent> -std::span<T, extent> createImplicitSpan(T* first, T* last) { - return {first, last}; // expected-error {{chosen constructor is explicit in copy-initialization}} -} - -int main(int, char**) -{ -// We can't check that the size doesn't match - because that's a runtime property -// std::span<int, 2> s1(arr, arr + 3); - -// Type wrong - { - std::span<float> s1(arr, arr + 3); // expected-error {{no matching constructor for initialization of 'std::span<float>'}} - std::span<float, 3> s2(arr, arr + 3); // expected-error {{no matching constructor for initialization of 'std::span<float, 3>'}} - } - -// CV wrong (dynamically sized) - { - std::span< int> s1{ carr, carr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span< int> s2{ varr, varr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span< int> s3{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} - std::span<const int> s4{ varr, varr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span<const int> s5{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} - std::span< volatile int> s6{ carr, carr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} - std::span< volatile int> s7{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} - } - -// CV wrong (statically sized) - { - std::span< int,3> s1{ carr, carr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<int, 3>'}} - std::span< int,3> s2{ varr, varr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<int, 3>'}} - std::span< int,3> s3{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<int, 3>'}} - std::span<const int,3> s4{ varr, varr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int, 3>'}} - std::span<const int,3> s5{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<const int, 3>'}} - std::span< volatile int,3> s6{ carr, carr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int, 3>'}} - std::span< volatile int,3> s7{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int, 3>'}} - } - - // explicit constructor necessary - { - createImplicitSpan<int, 1>(arr, arr + 1); - } - - return 0; -} diff --git a/libcxx/test/std/containers/views/span.cons/ptr_ptr.pass.cpp b/libcxx/test/std/containers/views/span.cons/ptr_ptr.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/containers/views/span.cons/ptr_ptr.pass.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// -*- C++ -*- -//===------------------------------ span ---------------------------------===// -// -// 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 - -// <span> - -// constexpr span(pointer first, pointer last); -// Requires: [first, last) shall be a valid range. -// If extent is not equal to dynamic_extent, then last - first shall be equal to extent. -// - -#include <span> -#include <cassert> -#include <string> - -#include "test_macros.h" - -void checkCV() -{ - int arr[] = {1,2,3}; - const int carr[] = {4,5,6}; - volatile int varr[] = {7,8,9}; - const volatile int cvarr[] = {1,3,5}; - -// Types the same (dynamic sized) - { - std::span< int> s1{ arr, arr + 3}; // a span< int> pointing at int. - std::span<const int> s2{ carr, carr + 3}; // a span<const int> pointing at const int. - std::span< volatile int> s3{ varr, varr + 3}; // a span< volatile int> pointing at volatile int. - std::span<const volatile int> s4{cvarr, cvarr + 3}; // a span<const volatile int> pointing at const volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); - } - -// Types the same (static sized) - { - std::span< int,3> s1{ arr, arr + 3}; // a span< int> pointing at int. - std::span<const int,3> s2{ carr, carr + 3}; // a span<const int> pointing at const int. - std::span< volatile int,3> s3{ varr, varr + 3}; // a span< volatile int> pointing at volatile int. - std::span<const volatile int,3> s4{cvarr, cvarr + 3}; // a span<const volatile int> pointing at const volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); - } - - -// types different (dynamic sized) - { - std::span<const int> s1{ arr, arr + 3}; // a span<const int> pointing at int. - std::span< volatile int> s2{ arr, arr + 3}; // a span< volatile int> pointing at int. - std::span< volatile int> s3{ arr, arr + 3}; // a span< volatile int> pointing at const int. - std::span<const volatile int> s4{ arr, arr + 3}; // a span<const volatile int> pointing at int. - std::span<const volatile int> s5{carr, carr + 3}; // a span<const volatile int> pointing at const int. - std::span<const volatile int> s6{varr, varr + 3}; // a span<const volatile int> pointing at volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); - } - -// types different (static sized) - { - std::span<const int,3> s1{ arr, arr + 3}; // a span<const int> pointing at int. - std::span< volatile int,3> s2{ arr, arr + 3}; // a span< volatile int> pointing at int. - std::span< volatile int,3> s3{ arr, arr + 3}; // a span< volatile int> pointing at const int. - std::span<const volatile int,3> s4{ arr, arr + 3}; // a span<const volatile int> pointing at int. - std::span<const volatile int,3> s5{carr, carr + 3}; // a span<const volatile int> pointing at const int. - std::span<const volatile int,3> s6{varr, varr + 3}; // a span<const volatile int> pointing at volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); - } -} - - -template <typename T> -constexpr bool testConstexprSpan() -{ - constexpr T val[2] = {}; - std::span<const T> s1{val, val+2}; - std::span<const T,2> s2{val, val+2}; - return - s1.data() == &val[0] && s1.size() == 2 - && s2.data() == &val[0] && s2.size() == 2; -} - - -template <typename T> -void testRuntimeSpan() -{ - T val[2] = {}; - std::span<T> s1{val, val+2}; - std::span<T,2> s2{val, val+2}; - assert(s1.data() == &val[0] && s1.size() == 2); - assert(s2.data() == &val[0] && s2.size() == 2); -} - -struct A{}; - -int main(int, char**) -{ - static_assert(testConstexprSpan<int>(), ""); - static_assert(testConstexprSpan<long>(), ""); - static_assert(testConstexprSpan<double>(), ""); - static_assert(testConstexprSpan<A>(), ""); - - testRuntimeSpan<int>(); - testRuntimeSpan<long>(); - testRuntimeSpan<double>(); - testRuntimeSpan<std::string>(); - testRuntimeSpan<A>(); - - checkCV(); - - return 0; -} diff --git a/libcxx/test/std/containers/views/span.cons/range.fail.cpp b/libcxx/test/std/containers/views/span.cons/range.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/span.cons/range.fail.cpp @@ -0,0 +1,119 @@ +//===------------------------------ span ---------------------------------===// +// +// 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-has-no-incomplete-ranges + +// <span> + +// template<class R> +// constexpr explicit(extent != dynamic_extent) span(R&& r); +// +// Let U be remove_reference_t<ranges::range_reference_t<R>>. +// Remarks: This constructor shall not participate in overload resolution unless: +// - R satisfies ranges::contiguous_range and ranges::sized_range, +// - Either R satisfies ranges::borrowed_range or is_const_v<element_type> is true, +// - remove_cvref_t<R> is not a specialization of span, +// - remove_cvref_t<R> is not a specialization of array, +// — is_array_v<remove_cvref_t<R>> is false, +// - is_convertible_v<U(*)[], element_type(*)[] is true +// + +#include <span> +#include <deque> +#include <forward_list> +#include <list> +#include <ranges> +#include <vector> + +#include "simple_range.h" +#include "test_macros.h" + +template <typename T> +struct IsARange { + T* begin(); + T* end(); +}; + +template <class T> +struct DisabledBorrowedRange { + T* begin(); + T* end(); +}; + +template <class T> +inline constexpr bool std::ranges::enable_borrowed_range<DisabledBorrowedRange<T>> = false; + +template<class T, std::size_t N> +struct SpecializationOfArray : std::array<T, N> {}; + +void check_type_wrong() { + SimpleRange<int, 1> r{}; + std::span<float> s1{r.begin(), r.end()}; // expected-error {{no matching constructor for initialization of 'std::span<float>'}} + std::span<float, 1> s2{r, 1}; // expected-error {{no matching constructor for initialization of 'std::span<float, 1>'}} + + std::span<const int> s3{std::deque<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} + std::span<const int> s4{std::list<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} + std::span<const int> s5{std::forward_list<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} +} + +void check_cv_dynamic_extent() { + IsARange<const int> c; + IsARange<const volatile int> cv; + IsARange<volatile int> v; + + std::span<int> s1{c}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} + std::span<int> s2{v}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} + std::span<int> s3{cv}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} + std::span<const int> s4{v}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} + std::span<const int> s5{cv}; // expected-error {{no matching constructor for initialization of 'std::span<const int>'}} + std::span<volatile int> s6{c}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} + std::span<volatile int> s7{cv}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}} +} +void check_invalid_range() { + std::span<int> s5{DisabledBorrowedRange<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} + std::span<int> s6{SpecializationOfArray<int, 1>()}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} +} + +void check_cv_static_extent() { + SimpleRange<const int, 1> c{}; + SimpleRange<const volatile int, 1> cv{}; + SimpleRange<volatile int, 1> v{}; + std::span<int, 1> s1{c}; // expected-error {{no matching constructor for initialization of 'std::span<int, 1>'}} + std::span<int, 1> s2{v}; // expected-error {{no matching constructor for initialization of 'std::span<int, 1>'}} + std::span<int, 1> s3{cv}; // expected-error {{no matching constructor for initialization of 'std::span<int, 1>'}} + std::span<const int, 1> s4{v}; // expected-error {{no matching constructor for initialization of 'std::span<const int, 1>'}} + std::span<const int, 1> s5{cv}; // expected-error {{no matching constructor for initialization of 'std::span<const int, 1>'}} + std::span<volatile int, 1> s6{c}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int, 1>'}} + std::span<volatile int, 1> s7{cv}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int, 1>'}} +} + +template<class T, size_t extent, class Range> +std::span<T, extent> createImplicitSpan(Range&& r) { + return {r}; // expected-error {{chosen constructor is explicit in copy-initialization}} +} + +void check_explicit_constructor() { + SimpleRange<int, 1> r{}; + createImplicitSpan<int, 1>(r); +} + +int main(int, char**) { + // Making non-const spans from const sources (a temporary binds to `const &`) + { + std::span<int> s1{IsARange<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} + std::span<int> s3{std::vector<int>()}; // expected-error {{no matching constructor for initialization of 'std::span<int>'}} + } + + check_type_wrong(); + check_invalid_range(); + check_cv_static_extent(); + check_cv_dynamic_extent(); + check_explicit_constructor(); + + return 0; +} diff --git a/libcxx/test/std/containers/views/span.cons/range.pass.cpp b/libcxx/test/std/containers/views/span.cons/range.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/span.cons/range.pass.cpp @@ -0,0 +1,88 @@ +//===------------------------------ span ---------------------------------===// +// +// 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-has-no-incomplete-ranges + +// <span> + +// template<class R> +// constexpr explicit(extent != dynamic_extent) span(R&& r); +// +// Let U be remove_reference_t<ranges::range_reference_t<R>>. +// Remarks: This constructor shall not participate in overload resolution unless: +// - R satisfies ranges::contiguous_range and ranges::sized_range, +// - Either R satisfies ranges::borrowed_range or is_const_v<element_type> is true, +// - remove_cvref_t<R> is not a specialization of span, +// - remove_cvref_t<R> is not a specialization of array, +// — is_array_v<remove_cvref_t<R>> is false, +// - is_convertible_v<rU(*)[], element_type(*)[] is true + + +#include <span> +#include <cassert> +#include <vector> + +#include "simple_range.h" +#include "test_macros.h" + +// TODO: convert to using std::is_constructible_v +void check_cv() +{ + std::vector<int> v = {1,2,3}; + +// types the same + { + std::span<int> s1{v}; + std::span<int, 3> s2{v}; + } + +// types different + { + std::span<const int> s1{v}; + std::span<const int, 3> s2{v}; + std::span<volatile int> s3{v}; + std::span<volatile int, 3> s4{v}; + std::span<const volatile int> s5{v}; + std::span<const volatile int, 3> s6{v}; + } + +// Constructing a const view from a temporary + { + std::span<const int> s1{std::vector<int>()}; + std::span<const int, 1> s2{std::vector<int>()}; + } +} + +template <class T, size_t Extent> +constexpr bool test_from_range() { + SimpleRange<T, 3> val{}; + std::span<T, Extent> s{val}; + assert(s.size() == val.size()); + assert(s.data() == val.data()); + return true; +} + +struct A{}; + +constexpr bool test() { + assert((test_from_range<int, std::dynamic_extent>())); + assert((test_from_range<int, 3>())); + assert((test_from_range<A, std::dynamic_extent>())); + assert((test_from_range<A, 3>())); + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + check_cv(); + + return 0; +} diff --git a/libcxx/test/std/containers/views/span.cons/simple_range.h b/libcxx/test/std/containers/views/span.cons/simple_range.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/span.cons/simple_range.h @@ -0,0 +1,30 @@ +#pragma once + +template <class T, size_t Size> +struct SimpleRange { + constexpr T *data() { + return elements; + } + constexpr const T *data() const { + return elements; + } + constexpr T *begin() { + return elements; + } + constexpr const T *begin() const { + return elements; + } + constexpr T *end() { + return elements + Size; + } + constexpr const T* end() const { + return elements + Size; + } + constexpr T const *getV() const { + return elements; + } + constexpr size_t size() const { + return Size; + } + T elements[Size]{}; +};