Commit 5d9b8a9f by Abseil Team Committed by Copybara-Service

Make Span complain if constructed with a parameter that won't outlive it, except…

Make Span complain if constructed with a parameter that won't outlive it, except if that parameter is also a span or appears to be a view type.

PiperOrigin-RevId: 461612357
Change-Id: Ibba36f44465176db47dd21e1866134549143fa64
parent 56f5477f
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
template <typename T>
class Span;
namespace span_internal { namespace span_internal {
// A constexpr min function // A constexpr min function
constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; } constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
...@@ -121,6 +124,36 @@ struct IsConvertible : IsConvertibleHelper<From, To>::type {}; ...@@ -121,6 +124,36 @@ struct IsConvertible : IsConvertibleHelper<From, To>::type {};
template <typename From, typename To> template <typename From, typename To>
using EnableIfConvertibleTo = using EnableIfConvertibleTo =
typename std::enable_if<IsConvertible<From, To>::value>::type; typename std::enable_if<IsConvertible<From, To>::value>::type;
// IsView is true for types where the return type of .data() is the same for
// mutable and const instances. This isn't foolproof, but it's only used to
// enable a compiler warning.
template <typename T, typename = void, typename = void>
struct IsView {
static constexpr bool value = false;
};
template <typename T>
struct IsView<
T, absl::void_t<decltype(span_internal::GetData(std::declval<const T&>()))>,
absl::void_t<decltype(span_internal::GetData(std::declval<T&>()))>> {
private:
using Container = std::remove_const_t<T>;
using ConstData =
decltype(span_internal::GetData(std::declval<const Container&>()));
using MutData = decltype(span_internal::GetData(std::declval<Container&>()));
public:
static constexpr bool value = std::is_same<ConstData, MutData>::value;
};
// These enablers result in 'int' so they can be used as typenames or defaults
// in template paramters lists.
template <typename T>
using EnableIfIsView = std::enable_if_t<IsView<T>::value, int>;
template <typename T>
using EnableIfNotIsView = std::enable_if_t<!IsView<T>::value, int>;
} // namespace span_internal } // namespace span_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "absl/base/attributes.h"
#include "absl/base/internal/throw_delegate.h" #include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
#include "absl/base/optimization.h" #include "absl/base/optimization.h"
...@@ -160,12 +161,12 @@ class Span { ...@@ -160,12 +161,12 @@ class Span {
// Used to SFINAE-enable a function when the slice elements are const. // Used to SFINAE-enable a function when the slice elements are const.
template <typename U> template <typename U>
using EnableIfConstView = using EnableIfValueIsConst =
typename std::enable_if<std::is_const<T>::value, U>::type; typename std::enable_if<std::is_const<T>::value, U>::type;
// Used to SFINAE-enable a function when the slice elements are mutable. // Used to SFINAE-enable a function when the slice elements are mutable.
template <typename U> template <typename U>
using EnableIfMutableView = using EnableIfValueIsMutable =
typename std::enable_if<!std::is_const<T>::value, U>::type; typename std::enable_if<!std::is_const<T>::value, U>::type;
public: public:
...@@ -196,13 +197,34 @@ class Span { ...@@ -196,13 +197,34 @@ class Span {
// Explicit reference constructor for a mutable `Span<T>` type. Can be // Explicit reference constructor for a mutable `Span<T>` type. Can be
// replaced with MakeSpan() to infer the type parameter. // replaced with MakeSpan() to infer the type parameter.
template <typename V, typename = EnableIfConvertibleFrom<V>, template <typename V, typename = EnableIfConvertibleFrom<V>,
typename = EnableIfMutableView<V>> typename = EnableIfValueIsMutable<V>,
explicit Span(V& v) noexcept // NOLINT(runtime/references) typename = span_internal::EnableIfNotIsView<V>>
explicit Span(
V& v
ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // NOLINT(runtime/references)
: Span(span_internal::GetData(v), v.size()) {} : Span(span_internal::GetData(v), v.size()) {}
// Implicit reference constructor for a read-only `Span<const T>` type // Implicit reference constructor for a read-only `Span<const T>` type
template <typename V, typename = EnableIfConvertibleFrom<V>, template <typename V, typename = EnableIfConvertibleFrom<V>,
typename = EnableIfConstView<V>> typename = EnableIfValueIsConst<V>,
typename = span_internal::EnableIfNotIsView<V>>
constexpr Span(
const V& v
ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // NOLINT(runtime/explicit)
: Span(span_internal::GetData(v), v.size()) {}
// Overloads of the above two functions that are only enabled for view types.
// This is so we can drop the ABSL_ATTRIBUTE_LIFETIME_BOUND annotation. These
// overloads must be made unique by using a different template parameter list
// (hence the = 0 for the IsView enabler).
template <typename V, typename = EnableIfConvertibleFrom<V>,
typename = EnableIfValueIsMutable<V>,
span_internal::EnableIfIsView<V> = 0>
explicit Span(V& v) noexcept // NOLINT(runtime/references)
: Span(span_internal::GetData(v), v.size()) {}
template <typename V, typename = EnableIfConvertibleFrom<V>,
typename = EnableIfValueIsConst<V>,
span_internal::EnableIfIsView<V> = 0>
constexpr Span(const V& v) noexcept // NOLINT(runtime/explicit) constexpr Span(const V& v) noexcept // NOLINT(runtime/explicit)
: Span(span_internal::GetData(v), v.size()) {} : Span(span_internal::GetData(v), v.size()) {}
...@@ -242,7 +264,7 @@ class Span { ...@@ -242,7 +264,7 @@ class Span {
// Process(ints); // Process(ints);
// //
template <typename LazyT = T, template <typename LazyT = T,
typename = EnableIfConstView<LazyT>> typename = EnableIfValueIsConst<LazyT>>
Span(std::initializer_list<value_type> v Span(std::initializer_list<value_type> v
ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // NOLINT(runtime/explicit) ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // NOLINT(runtime/explicit)
: Span(v.begin(), v.size()) {} : Span(v.begin(), v.size()) {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment