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
pull/1223/head
Abseil Team 3 years ago committed by Copybara-Service
parent 56f5477f15
commit 5d9b8a9fb0
  1. 33
      absl/types/internal/span.h
  2. 34
      absl/types/span.h

@ -28,6 +28,9 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
template <typename T>
class Span;
namespace span_internal {
// A constexpr min function
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 {};
template <typename From, typename To>
using EnableIfConvertibleTo =
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
ABSL_NAMESPACE_END
} // namespace absl

@ -60,6 +60,7 @@
#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
@ -160,12 +161,12 @@ class Span {
// Used to SFINAE-enable a function when the slice elements are const.
template <typename U>
using EnableIfConstView =
using EnableIfValueIsConst =
typename std::enable_if<std::is_const<T>::value, U>::type;
// Used to SFINAE-enable a function when the slice elements are mutable.
template <typename U>
using EnableIfMutableView =
using EnableIfValueIsMutable =
typename std::enable_if<!std::is_const<T>::value, U>::type;
public:
@ -196,13 +197,34 @@ class Span {
// Explicit reference constructor for a mutable `Span<T>` type. Can be
// replaced with MakeSpan() to infer the type parameter.
template <typename V, typename = EnableIfConvertibleFrom<V>,
typename = EnableIfMutableView<V>>
explicit Span(V& v) noexcept // NOLINT(runtime/references)
typename = EnableIfValueIsMutable<V>,
typename = span_internal::EnableIfNotIsView<V>>
explicit Span(
V& v
ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // NOLINT(runtime/references)
: Span(span_internal::GetData(v), v.size()) {}
// Implicit reference constructor for a read-only `Span<const T>` type
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)
: Span(span_internal::GetData(v), v.size()) {}
@ -242,7 +264,7 @@ class Span {
// Process(ints);
//
template <typename LazyT = T,
typename = EnableIfConstView<LazyT>>
typename = EnableIfValueIsConst<LazyT>>
Span(std::initializer_list<value_type> v
ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // NOLINT(runtime/explicit)
: Span(v.begin(), v.size()) {}

Loading…
Cancel
Save