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 `__","LWG","Fixing Atomic Initialization","Belfast","|Complete| [#note-P0883]_","13.0" "`P1391 `__","LWG","Range constructor for std::string_view","Belfast","* *","" -"`P1394 `__","LWG","Range constructor for std::span","Belfast","* *","" +"`P1394 `__","LWG","Range constructor for std::span","Belfast","|Complete|","14.0" "`P1456 `__","LWG","Move-only views","Belfast","* *","" "`P1622 `__","LWG","Mandating the Standard Library: Clause 32 - Thread support library","Belfast","* *","" "`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 + constexpr explicit(Extent != dynamic_extent) span(It first, size_type count); + template + constexpr explicit(Extent != dynamic_extent) span(It first, End last); template constexpr span(element_type (&arr)[N]) noexcept; template constexpr span(array& arr) noexcept; template constexpr span(const array& arr) noexcept; - template - constexpr explicit(Extent != dynamic_extent) span(Container& cont); - template - constexpr explicit(Extent != dynamic_extent) span(const Container& cont); + template + constexpr explicit(extent != dynamic_extent) span(R&& r); constexpr span(const span& other) noexcept = default; template constexpr explicit(Extent != dynamic_extent) span(const span& s) noexcept; @@ -108,6 +108,9 @@ size_type size_; // exposition only }; +template + span(It, EndOrSize) -> span>>; + template span(T (&)[N]) -> span; @@ -117,11 +120,8 @@ template span(const array&) -> span; -template - span(Container&) -> span; - -template - span(const Container&) -> span; +template + span(R&&) -> span>>; } // 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 // for array @@ -155,22 +158,16 @@ template -struct __is_span_impl : public false_type {}; +struct __is_std_array : false_type {}; -template -struct __is_span_impl> : public true_type {}; - -template -struct __is_span : public __is_span_impl> {}; +template +struct __is_std_array> : true_type {}; template -struct __is_std_array_impl : public false_type {}; +struct __is_std_span : false_type {}; template -struct __is_std_array_impl> : public true_type {}; - -template -struct __is_std_array : public __is_std_array_impl> {}; +struct __is_std_span> : true_type {}; template 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::value, nullptr_t>, + enable_if_t>::value, nullptr_t>, // is not a specialization of array - enable_if_t::value, nullptr_t>, + enable_if_t>::value, nullptr_t>, // is_array_v is false, enable_if_t, nullptr_t>, // data(cont) and size(cont) are well formed @@ -195,6 +192,17 @@ >> : public true_type {}; +#if !defined(_LIBCPP_HAS_NO_RANGES) +template +concept __is_span_compatible_range = + ranges::contiguous_range<_Range> && + ranges::sized_range<_Range> && + (ranges::borrowed_range<_Range> || is_const_v<_ElementType>) && + !__is_std_span>::value && + !__is_std_array>::value && + !is_array_v> && + is_convertible_v> (*)[], _ElementType(*)[]>; +#endif template class _LIBCPP_TEMPLATE_VIS span { @@ -224,10 +232,27 @@ 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 && + is_convertible_v > (*)[], 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 > (*)[], 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 +266,12 @@ _LIBCPP_INLINE_VISIBILITY constexpr span(const array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {} - template - _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 - _LIBCPP_INLINE_VISIBILITY - constexpr explicit span(const _Container& __c, - enable_if_t<__is_span_compatible_container::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 _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 _LIBCPP_INLINE_VISIBILITY @@ -402,8 +418,20 @@ 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(distance(__f, __l))} {} + template && + is_convertible_v > (*)[], 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 > (*)[], 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(_VSTD::distance(__first, __last))) {} template _LIBCPP_INLINE_VISIBILITY @@ -419,18 +447,10 @@ _LIBCPP_INLINE_VISIBILITY constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} - template - _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 - _LIBCPP_INLINE_VISIBILITY - constexpr span(const _Container& __c, - enable_if_t<__is_span_compatible_container::value, nullptr_t> = nullptr) - : __data{_VSTD::data(__c)}, __size{(size_type) _VSTD::size(__c)} {} - +# if !defined(_LIBCPP_HAS_NO_RANGES) + template <__is_span_compatible_range _Range> + _LIBCPP_INLINE_VISIBILITY constexpr span(_Range&& __r) : __data{ranges::data(__r)}, __size{ranges::size(__r)} {} +# endif template _LIBCPP_INLINE_VISIBILITY @@ -557,6 +577,9 @@ { return __s.__as_writable_bytes(); } // Deduction guides +template + span(_It, _EndOrSize) -> span>>; + template span(_Tp (&)[_Sz]) -> span<_Tp, _Sz>; @@ -566,11 +589,10 @@ template span(const array<_Tp, _Sz>&) -> span; -template - span(_Container&) -> span; - -template - span(const _Container&) -> span; +# if !defined(_LIBCPP_HAS_NO_RANGES) +template + span(_Range&&) -> span>>; +#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 - -// - -// template -// constexpr span(Container& cont); -// template -// 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 is false, -// — data(cont) and size(cont) are both well-formed, and -// — remove_pointer_t(*)[] is convertible to ElementType(*)[]. -// - -#include -#include -#include -#include -#include -#include - -#include "test_macros.h" - -// Look ma - I'm a container! -template -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 -struct NotAContainerNoData { - size_t size() const {return 0;} -}; - -template -struct NotAContainerNoSize { - const T *data() const {return nullptr;} -}; - -template -struct NotAContainerPrivate { -private: - size_t size() const {return 0;} - const T *data() const {return nullptr;} -}; - -template -std::span 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 s1{IsAContainer()}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s3{std::vector()}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// Missing size and/or data - { - std::span s1{NotAContainerNoData()}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s3{NotAContainerNoSize()}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s5{NotAContainerPrivate()}; // expected-error {{no matching constructor for initialization of 'std::span'}} - -// Again with the standard containers - std::span s11{std::deque()}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s13{std::list()}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s15{std::forward_list()}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// Not the same type - { - IsAContainer c; - std::span s1{c}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// CV wrong - { - IsAContainer c; - IsAContainer cv; - IsAContainer< volatile int> v; - - std::span< int> s1{c}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int> s2{v}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int> s3{cv}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s4{v}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s5{cv}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int> s6{c}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int> s7{cv}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// explicit constructor necessary - { - IsAContainer c; - const IsAContainer cc; - - createImplicitSpan(c); - createImplicitSpan(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 - -// - -// template -// constexpr span(Container& cont); -// template -// 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 is false, -// — data(cont) and size(cont) are both well-formed, and -// — remove_pointer_t(*)[] is convertible to ElementType(*)[]. -// - - -#include -#include -#include -#include - -#include "test_macros.h" - -// Look ma - I'm a container! -template -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 v = {1,2,3}; - -// Types the same - { - std::span< int> s1{v}; // a span< int> pointing at int. - } - -// types different - { - std::span s1{v}; // a span 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 s4{v}; // a span pointing at int. - } - -// Constructing a const view from a temporary - { - std::span s1{IsAContainer()}; - std::span s3{std::vector()}; - (void) s1; - (void) s3; - } -} - - -template -constexpr bool testConstexprSpan() -{ - constexpr IsAContainer val{}; - std::span s1{val}; - return s1.data() == val.getV() && s1.size() == 1; -} - -template -constexpr bool testConstexprSpanStatic() -{ - constexpr IsAContainer val{}; - std::span s1{val}; - return s1.data() == val.getV() && s1.size() == 1; -} - -template -void testRuntimeSpan() -{ - IsAContainer val{}; - const IsAContainer cVal; - std::span s1{val}; - std::span s2{cVal}; - assert(s1.data() == val.getV() && s1.size() == 1); - assert(s2.data() == cVal.getV() && s2.size() == 1); -} - -template -void testRuntimeSpanStatic() -{ - IsAContainer val{}; - const IsAContainer cVal; - std::span s1{val}; - std::span 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(), ""); - static_assert(testConstexprSpan(), ""); - static_assert(testConstexprSpan(), ""); - static_assert(testConstexprSpan(), ""); - - static_assert(testConstexprSpanStatic(), ""); - static_assert(testConstexprSpanStatic(), ""); - static_assert(testConstexprSpanStatic(), ""); - static_assert(testConstexprSpanStatic(), ""); - - testRuntimeSpan(); - testRuntimeSpan(); - testRuntimeSpan(); - testRuntimeSpan(); - testRuntimeSpan(); - - testRuntimeSpanStatic(); - testRuntimeSpanStatic(); - testRuntimeSpanStatic(); - testRuntimeSpanStatic(); - testRuntimeSpanStatic(); - - 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 // +// template +// span(It, EndOrSize) -> span>>; +// // template // span(T (&)[N]) -> span; // @@ -19,12 +22,8 @@ // template // span(const array&) -> span; // -// template -// span(Container&) -> span; -// -// template -// span(const Container&) -> span; - +// template +// span(R&&) -> span>>; #include @@ -35,10 +34,25 @@ #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); + 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); + 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); assert(s.size() == std::size(arr)); @@ -52,7 +66,9 @@ assert(s.size() == std::size(arr)); assert(s.data() == std::data(arr)); } +} +void test_std_array() { { std::array arr = {1.0, 2.0, 3.0, 4.0}; std::span s{arr}; @@ -68,7 +84,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 +102,14 @@ assert(s.size() == str.size()); assert(s.data() == str.data()); } +} + +int main(int, char**) +{ + test_iterator_sentinel(); + test_c_array(); + test_std_array(); + test_range_std_container(); 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,32 @@ +//===------------------------------ 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 + +// + +// template +// 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 + +template +std::span createImplicitSpan(T* first, T* last) { + return {first, last}; // expected-error {{chosen constructor is explicit in copy-initialization}} +} + +int main(int, char**) { + // explicit constructor necessary + int arr[] = {1, 2, 3}; + createImplicitSpan(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,60 @@ +//===------------------------------ 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 + +// + +// template +// 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 +#include + +template +constexpr bool test_ctor() { + T val[2] = {}; + auto s1 = std::span(std::begin(val), std::end(val)); + auto s2 = std::span(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; +} + +template +constexpr void test_constructability() { + static_assert(std::is_constructible_v, int*, int*>); + static_assert(!std::is_constructible_v, const int*, const int*>); + static_assert(!std::is_constructible_v, volatile int*, volatile int*>); + static_assert(std::is_constructible_v, int*, int*>); + static_assert(std::is_constructible_v, const int*, const int*>); + static_assert(!std::is_constructible_v, volatile int*, volatile int*>); + static_assert(std::is_constructible_v, int*, int*>); + static_assert(!std::is_constructible_v, const int*, const int*>); + static_assert(std::is_constructible_v, volatile int*, volatile int*>); + static_assert(!std::is_constructible_v, int*, float*>); // types wrong +} + +constexpr bool test() { + test_constructability(); + test_constructability<3>(); + struct A {}; + assert(test_ctor()); + assert(test_ctor()); + return true; +} + +int main(int, char**) { + static_assert(test()); + assert(test()); + + 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,31 @@ +//===------------------------------ 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 + +// + +// template +// 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 + +template +std::span createImplicitSpan(T* ptr, size_t len) { + return {ptr, len}; // expected-error {{chosen constructor is explicit in copy-initialization}} +} + +int main(int, char**) { + // explicit constructor necessary + int arr[] = {1, 2, 3}; + createImplicitSpan(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,68 @@ +//===------------------------------ 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 + +// + +// template +// 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 +#include +#include + +template +constexpr void test_constructability() { + struct Other {}; + static_assert(std::is_constructible_v, int*, size_t>); + static_assert(!std::is_constructible_v, const int*, size_t>); + static_assert(std::is_constructible_v, int*, size_t>); + static_assert(std::is_constructible_v, const int*, size_t>); + static_assert(!std::is_constructible_v, volatile int*, size_t>); + static_assert(!std::is_constructible_v, const volatile int*, size_t>); + static_assert(!std::is_constructible_v, volatile int*, size_t>); + static_assert(!std::is_constructible_v, const volatile int*, size_t>); + static_assert(!std::is_constructible_v, const int*, size_t>); + static_assert(!std::is_constructible_v, const volatile int*, size_t>); + static_assert( + !std::is_constructible_v, double*, size_t>); // iterator type differs from span type + static_assert(!std::is_constructible_v, size_t, size_t>); + static_assert(!std::is_constructible_v, Other*, size_t>); // unrelated iterator type +} + +template +constexpr bool test_ctor() { + T val[2] = {}; + auto s1 = std::span(val, 2); + auto s2 = std::span(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; +} + +constexpr bool test() { + test_constructability(); + test_constructability<3>(); + + struct A {}; + test_ctor(); + test_ctor(); + + return true; +} + +int main(int, char**) { + assert(test()); + static_assert(test()); + + 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 - -// - -// 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 -#include -#include - -#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 -std::span 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 s1(arr, 3); - -// Type wrong - { - std::span s1(arr, 3); // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s2(arr, 3); // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// CV wrong (dynamically sized) - { - std::span< int> s1{ carr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int> s2{ varr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int> s3{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s4{ varr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s5{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int> s6{ carr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int> s7{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// CV wrong (statically sized) - { - std::span< int,3> s1{ carr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int,3> s2{ varr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int,3> s3{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s4{ varr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s5{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int,3> s6{ carr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int,3> s7{cvarr, 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// explicit constructor necessary - { - createImplicitSpan(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 - -// - -// 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 -#include -#include - -#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 s2{ carr, 3}; // a span pointing at const int. - std::span< volatile int> s3{ varr, 3}; // a span< volatile int> pointing at volatile int. - std::span s4{cvarr, 3}; // a span 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 s2{ carr, 3}; // a span pointing at const int. - std::span< volatile int,3> s3{ varr, 3}; // a span< volatile int> pointing at volatile int. - std::span s4{cvarr, 3}; // a span pointing at const volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); - } - - -// types different (dynamic sized) - { - std::span s1{ arr, 3}; // a span 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 s4{ arr, 3}; // a span pointing at int. - std::span s5{carr, 3}; // a span pointing at const int. - std::span s6{varr, 3}; // a span pointing at volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); - } - -// types different (static sized) - { - std::span s1{ arr, 3}; // a span 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 s4{ arr, 3}; // a span pointing at int. - std::span s5{carr, 3}; // a span pointing at const int. - std::span s6{varr, 3}; // a span pointing at volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); - } -} - - -template -constexpr bool testConstexprSpan() -{ - constexpr T val[2] = {}; - std::span s1{val, 2}; - std::span s2{val, 2}; - return - s1.data() == &val[0] && s1.size() == 2 - && s2.data() == &val[0] && s2.size() == 2; -} - - -template -void testRuntimeSpan() -{ - T val[2] = {}; - std::span s1{val, 2}; - std::span 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(), ""); - static_assert(testConstexprSpan(), ""); - static_assert(testConstexprSpan(), ""); - static_assert(testConstexprSpan(), ""); - - testRuntimeSpan(); - testRuntimeSpan(); - testRuntimeSpan(); - testRuntimeSpan(); - testRuntimeSpan(); - - 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 - -// - -// 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 -#include -#include - -#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 -std::span 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 s1(arr, arr + 3); - -// Type wrong - { - std::span s1(arr, arr + 3); // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s2(arr, arr + 3); // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// CV wrong (dynamically sized) - { - std::span< int> s1{ carr, carr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int> s2{ varr, varr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int> s3{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s4{ varr, varr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s5{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int> s6{ carr, carr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int> s7{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// CV wrong (statically sized) - { - std::span< int,3> s1{ carr, carr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int,3> s2{ varr, varr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int,3> s3{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s4{ varr, varr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s5{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int,3> s6{ carr, carr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int,3> s7{cvarr, cvarr + 3}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - - // explicit constructor necessary - { - createImplicitSpan(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 - -// - -// 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 -#include -#include - -#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 s2{ carr, carr + 3}; // a span pointing at const int. - std::span< volatile int> s3{ varr, varr + 3}; // a span< volatile int> pointing at volatile int. - std::span s4{cvarr, cvarr + 3}; // a span 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 s2{ carr, carr + 3}; // a span pointing at const int. - std::span< volatile int,3> s3{ varr, varr + 3}; // a span< volatile int> pointing at volatile int. - std::span s4{cvarr, cvarr + 3}; // a span pointing at const volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() == 12); - } - - -// types different (dynamic sized) - { - std::span s1{ arr, arr + 3}; // a span 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 s4{ arr, arr + 3}; // a span pointing at int. - std::span s5{carr, carr + 3}; // a span pointing at const int. - std::span s6{varr, varr + 3}; // a span pointing at volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); - } - -// types different (static sized) - { - std::span s1{ arr, arr + 3}; // a span 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 s4{ arr, arr + 3}; // a span pointing at int. - std::span s5{carr, carr + 3}; // a span pointing at const int. - std::span s6{varr, varr + 3}; // a span pointing at volatile int. - assert(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size() == 18); - } -} - - -template -constexpr bool testConstexprSpan() -{ - constexpr T val[2] = {}; - std::span s1{val, val+2}; - std::span s2{val, val+2}; - return - s1.data() == &val[0] && s1.size() == 2 - && s2.data() == &val[0] && s2.size() == 2; -} - - -template -void testRuntimeSpan() -{ - T val[2] = {}; - std::span s1{val, val+2}; - std::span 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(), ""); - static_assert(testConstexprSpan(), ""); - static_assert(testConstexprSpan(), ""); - static_assert(testConstexprSpan(), ""); - - testRuntimeSpan(); - testRuntimeSpan(); - testRuntimeSpan(); - testRuntimeSpan(); - testRuntimeSpan(); - - checkCV(); - - 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,93 @@ +//===------------------------------ 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 + +// + +// template +// constexpr explicit(extent != dynamic_extent) span(R&& r); +// +// Let U be remove_reference_t>. +// 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 is true, +// - remove_cvref_t is not a specialization of span, +// - remove_cvref_t is not a specialization of array, +// — is_array_v> is false, +// - is_convertible_v +#include +#include +#include +#include +#include +#include + +template +constexpr bool test_from_range() { + T val[3]{}; + std::span s{val}; + assert(s.size() == std::size(val)); + assert(s.data() == std::data(val)); + return true; +} + +struct A {}; + +constexpr bool test() { + assert((test_from_range())); + assert((test_from_range())); + assert((test_from_range())); + assert((test_from_range())); + return true; +} + +static_assert(!std::is_constructible_v, std::vector&>); // wrong type +static_assert(!std::is_constructible_v, std::vector&>); // wrong type + +static_assert(std::is_constructible_v, std::vector&>); // non-borrowed lvalue +static_assert(std::is_constructible_v, std::vector&>); // non-borrowed lvalue +static_assert(!std::is_constructible_v, const std::vector&>); // non-borrowed const lvalue +static_assert(!std::is_constructible_v, const std::vector&>); // non-borrowed const lvalue +static_assert(std::is_constructible_v, const std::vector&>); // non-borrowed const lvalue +static_assert(std::is_constructible_v, const std::vector&>); // non-borrowed const lvalue +static_assert(std::is_constructible_v, std::vector&>); // non-borrowed lvalue +static_assert(std::is_constructible_v, std::vector&>); // non-borrowed lvalue +static_assert(!std::is_constructible_v, std::vector&&>); // non-borrowed rvalue +static_assert(!std::is_constructible_v, std::vector&&>); // non-borrowed rvalue +static_assert(!std::is_constructible_v, std::deque&>); // non-contiguous lvalue +static_assert(!std::is_constructible_v, std::deque&>); // non-contiguous lvalue +static_assert(!std::is_constructible_v< + std::span, std::ranges::subrange::iterator, + std::deque::iterator>&&>); // non-contiguous borrowed rvalue +static_assert(!std::is_constructible_v< + std::span, std::ranges::subrange::iterator, + std::deque::iterator>&&>); // non-contiguous borrowed rvalue + +using BorrowedContiguousSizedRange = std::string_view; +static_assert(std::is_constructible_v, BorrowedContiguousSizedRange>); +static_assert(std::is_constructible_v, BorrowedContiguousSizedRange>); +static_assert(!std::is_constructible_v, BorrowedContiguousSizedRange>); +static_assert(!std::is_constructible_v, BorrowedContiguousSizedRange>); + +static_assert(std::is_convertible_v >); +static_assert(!std::is_convertible_v >); +static_assert(!std::is_convertible_v >); +static_assert(!std::is_convertible_v >); +static_assert(std::is_convertible_v >); +static_assert(!std::is_convertible_v >); + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}