[libcxx-commits] [libcxx] 6d2599e - [libcxx][span] Implement P1976R2
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Wed May 13 06:53:11 PDT 2020
Author: Michael Schellenberger Costa
Date: 2020-05-13T09:52:47-04:00
New Revision: 6d2599e4f776d0cd88438cb82a00c4fc25cc3f67
URL: https://github.com/llvm/llvm-project/commit/6d2599e4f776d0cd88438cb82a00c4fc25cc3f67
DIFF: https://github.com/llvm/llvm-project/commit/6d2599e4f776d0cd88438cb82a00c4fc25cc3f67.diff
LOG: [libcxx][span] Implement P1976R2
This resolves the NB comment about the construction of a fixed-size span
from a dynamic range.
Differential Revision: https://reviews.llvm.org/D74577
Added:
libcxx/test/std/language.support/support.limits/support.limits.general/span.version.pass.cpp
Modified:
libcxx/docs/FeatureTestMacroTable.rst
libcxx/include/span
libcxx/include/version
libcxx/test/std/containers/views/span.cons/assign.pass.cpp
libcxx/test/std/containers/views/span.cons/container.fail.cpp
libcxx/test/std/containers/views/span.cons/container.pass.cpp
libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp
libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp
libcxx/test/std/containers/views/span.cons/span.fail.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
libcxx/utils/generate_feature_test_macro_components.py
Removed:
################################################################################
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 937683d9cc12..77c7c68cf962 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -198,6 +198,8 @@ Status
------------------------------------------------- -----------------
``__cpp_lib_ranges`` *unimplemented*
------------------------------------------------- -----------------
+ ``__cpp_lib_span`` ``202002L``
+ ------------------------------------------------- -----------------
``__cpp_lib_three_way_comparison`` *unimplemented*
------------------------------------------------- -----------------
``__cpp_lib_to_array`` ``201907L``
diff --git a/libcxx/include/span b/libcxx/include/span
index 1fe1496530e9..018bf5190573 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -53,8 +53,8 @@ public:
// [span.cons], span constructors, copy, assignment, and destructor
constexpr span() noexcept;
- constexpr span(pointer ptr, size_type count);
- constexpr span(pointer firstElem, pointer lastElem);
+ constexpr explicit(Extent != dynamic_extent) span(pointer ptr, size_type count);
+ constexpr explicit(Extent != dynamic_extent) span(pointer firstElem, pointer lastElem);
template <size_t N>
constexpr span(element_type (&arr)[N]) noexcept;
template <size_t N>
@@ -62,12 +62,12 @@ public:
template <size_t N>
constexpr span(const array<value_type, N>& arr) noexcept;
template <class Container>
- constexpr span(Container& cont);
+ constexpr explicit(Extent != dynamic_extent) span(Container& cont);
template <class Container>
- constexpr span(const Container& cont);
+ constexpr explicit(Extent != dynamic_extent) span(const Container& cont);
constexpr span(const span& other) noexcept = default;
template <class OtherElementType, size_t OtherExtent>
- constexpr span(const span<OtherElementType, OtherExtent>& s) noexcept;
+ constexpr explicit(Extent != dynamic_extent) span(const span<OtherElementType, OtherExtent>& s) noexcept;
~span() noexcept = default;
constexpr span& operator=(const span& other) noexcept = default;
@@ -214,15 +214,31 @@ public:
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}
+ _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 span(pointer __f, pointer __l) : __data{__f}
+ _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)"); }
_LIBCPP_INLINE_VISIBILITY constexpr span(element_type (&__arr)[_Extent]) noexcept : __data{__arr} {}
_LIBCPP_INLINE_VISIBILITY constexpr span( array<value_type, _Extent>& __arr) noexcept : __data{__arr.data()} {}
_LIBCPP_INLINE_VISIBILITY constexpr span(const array<value_type, _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)");
+ }
+
template <class _OtherElementType>
_LIBCPP_INLINE_VISIBILITY
constexpr span(const span<_OtherElementType, _Extent>& __other,
@@ -233,7 +249,7 @@ public:
template <class _OtherElementType>
_LIBCPP_INLINE_VISIBILITY
- constexpr span(const span<_OtherElementType, dynamic_extent>& __other,
+ constexpr explicit span(const span<_OtherElementType, dynamic_extent>& __other,
enable_if_t<
is_convertible_v<_OtherElementType(*)[], element_type (*)[]>,
nullptr_t> = nullptr) noexcept
@@ -247,7 +263,7 @@ public:
constexpr span<element_type, _Count> first() const noexcept
{
static_assert(_Count <= _Extent, "Count out of range in span::first()");
- return {data(), _Count};
+ return span<element_type, _Count>{data(), _Count};
}
template <size_t _Count>
@@ -255,7 +271,7 @@ public:
constexpr span<element_type, _Count> last() const noexcept
{
static_assert(_Count <= _Extent, "Count out of range in span::last()");
- return {data() + size() - _Count, _Count};
+ return span<element_type, _Count>{data() + size() - _Count, _Count};
}
_LIBCPP_INLINE_VISIBILITY
@@ -279,7 +295,9 @@ public:
{
static_assert(_Offset <= _Extent, "Offset out of range in span::subspan()");
static_assert(_Count == dynamic_extent || _Count <= _Extent - _Offset, "Offset + count out of range in span::subspan()");
- return {data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
+
+ using _ReturnType = span<element_type, _Count != dynamic_extent ? _Count : _Extent - _Offset>;
+ return _ReturnType{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
}
@@ -337,10 +355,10 @@ public:
}
_LIBCPP_INLINE_VISIBILITY span<const byte, _Extent * sizeof(element_type)> __as_bytes() const noexcept
- { return {reinterpret_cast<const byte *>(data()), size_bytes()}; }
+ { return span<const byte, _Extent * sizeof(element_type)>{reinterpret_cast<const byte *>(data()), size_bytes()}; }
_LIBCPP_INLINE_VISIBILITY span<byte, _Extent * sizeof(element_type)> __as_writable_bytes() const noexcept
- { return {reinterpret_cast<byte *>(data()), size_bytes()}; }
+ { return span<byte, _Extent * sizeof(element_type)>{reinterpret_cast<byte *>(data()), size_bytes()}; }
private:
pointer __data;
@@ -418,7 +436,7 @@ public:
constexpr span<element_type, _Count> first() const noexcept
{
_LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::first()");
- return {data(), _Count};
+ return span<element_type, _Count>{data(), _Count};
}
template <size_t _Count>
@@ -426,7 +444,7 @@ public:
constexpr span<element_type, _Count> last() const noexcept
{
_LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::last()");
- return {data() + size() - _Count, _Count};
+ return span<element_type, _Count>{data() + size() - _Count, _Count};
}
_LIBCPP_INLINE_VISIBILITY
@@ -449,7 +467,7 @@ public:
{
_LIBCPP_ASSERT(_Offset <= size(), "Offset out of range in span::subspan()");
_LIBCPP_ASSERT(_Count == dynamic_extent || _Count <= size() - _Offset, "Offset + count out of range in span::subspan()");
- return {data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
+ return span<element_type, _Count>{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
}
constexpr span<element_type, dynamic_extent>
diff --git a/libcxx/include/version b/libcxx/include/version
index c2e99ccd9a90..46b0d65cb29b 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -98,6 +98,7 @@ __cpp_lib_shared_mutex 201505L <shared_mutex>
__cpp_lib_shared_ptr_arrays 201611L <memory>
__cpp_lib_shared_ptr_weak_type 201606L <memory>
__cpp_lib_shared_timed_mutex 201402L <shared_mutex>
+__cpp_lib_span 202002L <span>
__cpp_lib_string_udls 201304L <string>
__cpp_lib_string_view 201606L <string> <string_view>
__cpp_lib_three_way_comparison 201711L <compare>
@@ -234,8 +235,9 @@ __cpp_lib_void_t 201411L <type_traits>
# endif
# define __cpp_lib_list_remove_return_type 201806L
// # define __cpp_lib_ranges 201811L
-# define __cpp_lib_to_array 201907L
+# define __cpp_lib_span 202002L
// # define __cpp_lib_three_way_comparison 201711L
+# define __cpp_lib_to_array 201907L
#endif
#endif // _LIBCPP_VERSIONH
diff --git a/libcxx/test/std/containers/views/span.cons/assign.pass.cpp b/libcxx/test/std/containers/views/span.cons/assign.pass.cpp
index cde1e168431d..e0973e73034e 100644
--- a/libcxx/test/std/containers/views/span.cons/assign.pass.cpp
+++ b/libcxx/test/std/containers/views/span.cons/assign.pass.cpp
@@ -185,13 +185,14 @@ int main(int, char**)
// constexpr statically sized assignment
{
- constexpr std::span<const int,2> spans[] = {
- {carr1, 2},
- {carr1 + 1, 2},
- {carr1 + 2, 2},
- {carr2, 2},
- {carr2 + 1, 2},
- {carr3, 2}
+ using spanType = std::span<const int,2>;
+ constexpr spanType spans[] = {
+ spanType{carr1, 2},
+ spanType{carr1 + 1, 2},
+ spanType{carr1 + 2, 2},
+ spanType{carr2, 2},
+ spanType{carr2 + 1, 2},
+ spanType{carr3, 2}
};
static_assert(std::size(spans) == 6, "" );
@@ -247,10 +248,11 @@ int main(int, char**)
// statically sized assignment
{
- std::span<int,2> spans[] = {
- {arr, arr + 2},
- {arr + 1, arr + 3},
- {arr + 2, arr + 4}
+ using spanType = std::span<int,2>;
+ spanType spans[] = {
+ spanType{arr, arr + 2},
+ spanType{arr + 1, arr + 3},
+ spanType{arr + 2, arr + 4}
};
for (size_t i = 0; i < std::size(spans); ++i)
@@ -279,10 +281,11 @@ int main(int, char**)
}
{
- std::span<std::string, 1> spans[] = {
- {strs, strs + 1},
- {strs + 1, strs + 2},
- {strs + 2, strs + 3}
+ using spanType = std::span<std::string, 1>;
+ spanType spans[] = {
+ spanType{strs, strs + 1},
+ spanType{strs + 1, strs + 2},
+ spanType{strs + 2, strs + 3}
};
for (size_t i = 0; i < std::size(spans); ++i)
diff --git a/libcxx/test/std/containers/views/span.cons/container.fail.cpp b/libcxx/test/std/containers/views/span.cons/container.fail.cpp
index b0b753cbd2dc..81abde99be3a 100644
--- a/libcxx/test/std/containers/views/span.cons/container.fail.cpp
+++ b/libcxx/test/std/containers/views/span.cons/container.fail.cpp
@@ -63,6 +63,10 @@ struct NotAContainerPrivate {
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**)
{
@@ -106,12 +110,14 @@ int main(int, char**)
std::span< volatile int> s7{cv}; // expected-error {{no matching constructor for initialization of 'std::span<volatile int>'}}
}
-// statically sized
+// explicit constructor necessary
{
- IsAContainer<int> c;
- std::span<int,1> s1{c}; // expected-error {{no matching constructor for initialization of 'std::span<int, 1>'}}
- }
+ 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
index d4758c694ee2..af28cceed9e4 100644
--- a/libcxx/test/std/containers/views/span.cons/container.pass.cpp
+++ b/libcxx/test/std/containers/views/span.cons/container.pass.cpp
@@ -84,14 +84,32 @@ constexpr bool testConstexprSpan()
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};
+ 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);
}
@@ -105,12 +123,23 @@ int main(int, char**)
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/ptr_len.fail.cpp b/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp
index 05dbcf8d1cd5..8ec377142420 100644
--- a/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp
+++ b/libcxx/test/std/containers/views/span.cons/ptr_len.fail.cpp
@@ -27,6 +27,11 @@ 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
@@ -60,5 +65,10 @@ int main(int, char**)
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_ptr.fail.cpp b/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp
index 9c15ea58c952..73ef48011744 100644
--- a/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp
+++ b/libcxx/test/std/containers/views/span.cons/ptr_ptr.fail.cpp
@@ -27,6 +27,11 @@ 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
@@ -60,5 +65,10 @@ int main(int, char**)
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/span.fail.cpp b/libcxx/test/std/containers/views/span.cons/span.fail.cpp
index c303719fd016..03ff2e636c67 100644
--- a/libcxx/test/std/containers/views/span.cons/span.fail.cpp
+++ b/libcxx/test/std/containers/views/span.cons/span.fail.cpp
@@ -24,6 +24,11 @@
#include "test_macros.h"
+template<class T, size_t extent, size_t otherExtent>
+std::span<T, extent> createImplicitSpan(std::span<T, otherExtent> s) {
+ return {s}; // expected-error {{chosen constructor is explicit in copy-initialization}}
+}
+
void checkCV ()
{
// std::span< int> sp;
@@ -101,5 +106,10 @@ int main(int, char**)
checkCV();
+ // explicit constructor necessary
+ {
+ createImplicitSpan<int, 1>(sp);
+ }
+
return 0;
}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.pass.cpp
new file mode 100644
index 000000000000..c1a9f8632705
--- /dev/null
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/span.version.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// WARNING: This test was generated by generate_feature_test_macro_components.py
+// and should not be edited manually.
+
+// <span>
+
+// Test the feature test macros defined by <span>
+
+/* Constant Value
+ __cpp_lib_span 202002L [C++2a]
+*/
+
+#include <span>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 14
+
+# ifdef __cpp_lib_span
+# error "__cpp_lib_span should not be defined before c++2a"
+# endif
+
+#elif TEST_STD_VER == 14
+
+# ifdef __cpp_lib_span
+# error "__cpp_lib_span should not be defined before c++2a"
+# endif
+
+#elif TEST_STD_VER == 17
+
+# ifdef __cpp_lib_span
+# error "__cpp_lib_span should not be defined before c++2a"
+# endif
+
+#elif TEST_STD_VER > 17
+
+# ifndef __cpp_lib_span
+# error "__cpp_lib_span should be defined in c++2a"
+# endif
+# if __cpp_lib_span != 202002L
+# error "__cpp_lib_span should have the value 202002L in c++2a"
+# endif
+
+#endif // TEST_STD_VER > 17
+
+int main(int, char**) { return 0; }
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
index 081f0fede234..34e59e038546 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
@@ -85,6 +85,7 @@
__cpp_lib_shared_ptr_arrays 201611L [C++17]
__cpp_lib_shared_ptr_weak_type 201606L [C++17]
__cpp_lib_shared_timed_mutex 201402L [C++14]
+ __cpp_lib_span 202002L [C++2a]
__cpp_lib_string_udls 201304L [C++14]
__cpp_lib_string_view 201606L [C++17]
__cpp_lib_three_way_comparison 201711L [C++2a]
@@ -391,6 +392,10 @@
# error "__cpp_lib_shared_timed_mutex should not be defined before c++14"
# endif
+# ifdef __cpp_lib_span
+# error "__cpp_lib_span should not be defined before c++2a"
+# endif
+
# ifdef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should not be defined before c++14"
# endif
@@ -784,6 +789,10 @@
# endif
# endif
+# ifdef __cpp_lib_span
+# error "__cpp_lib_span should not be defined before c++2a"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++14"
# endif
@@ -1381,6 +1390,10 @@
# endif
# endif
+# ifdef __cpp_lib_span
+# error "__cpp_lib_span should not be defined before c++2a"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++17"
# endif
@@ -2116,6 +2129,13 @@
# endif
# endif
+# ifndef __cpp_lib_span
+# error "__cpp_lib_span should be defined in c++2a"
+# endif
+# if __cpp_lib_span != 202002L
+# error "__cpp_lib_span should have the value 202002L in c++2a"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++2a"
# endif
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 96860c2118c2..d19e358482b5 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -591,6 +591,12 @@ def add_version_header(tc):
},
"headers": ["array"],
},
+ {"name": "__cpp_lib_span",
+ "values": {
+ "c++2a": int(202002),
+ },
+ "headers": ["span"],
+ },
]], key=lambda tc: tc["name"])
def get_std_dialects():
More information about the libcxx-commits
mailing list