[ArrayRef] Provide constructors from any type with a data() member (#145735)
The assumption here is that if data() returns a pointer and size() exists it's something representing contiguous storage. Modeled after the behavior of C++20 std::span and enables two-way conversion between std::span (or really any span-like type) and ArrayRef. Add a unit test that verifies this if std::span is around. This also means we can get rid of specific conversions for std::vector and SmallVector.
This commit is contained in:
@@ -84,18 +84,19 @@ namespace llvm {
|
||||
assert(begin <= end);
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a SmallVector. This is templated in order to
|
||||
/// avoid instantiating SmallVectorTemplateCommon<T> whenever we
|
||||
/// copy-construct an ArrayRef.
|
||||
template<typename U>
|
||||
/*implicit*/ ArrayRef(const SmallVectorTemplateCommon<T, U> &Vec)
|
||||
: Data(Vec.data()), Length(Vec.size()) {
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a std::vector.
|
||||
template<typename A>
|
||||
/*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
|
||||
: Data(Vec.data()), Length(Vec.size()) {}
|
||||
/// Construct an ArrayRef from a type that has a data() method that returns
|
||||
/// a pointer convertible to const T *.
|
||||
template <
|
||||
typename C,
|
||||
typename = std::enable_if_t<
|
||||
std::conjunction_v<
|
||||
std::is_convertible<
|
||||
decltype(std::declval<const C &>().data()) *,
|
||||
const T *const *>,
|
||||
std::is_integral<decltype(std::declval<const C &>().size())>>,
|
||||
void>>
|
||||
/*implicit*/ constexpr ArrayRef(const C &V)
|
||||
: Data(V.data()), Length(V.size()) {}
|
||||
|
||||
/// Construct an ArrayRef from a std::array
|
||||
template <size_t N>
|
||||
@@ -123,32 +124,6 @@ namespace llvm {
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/// Construct an ArrayRef<const T*> from ArrayRef<T*>. This uses SFINAE to
|
||||
/// ensure that only ArrayRefs of pointers can be converted.
|
||||
template <typename U>
|
||||
ArrayRef(const ArrayRef<U *> &A,
|
||||
std::enable_if_t<std::is_convertible<U *const *, T const *>::value>
|
||||
* = nullptr)
|
||||
: Data(A.data()), Length(A.size()) {}
|
||||
|
||||
/// Construct an ArrayRef<const T*> from a SmallVector<T*>. This is
|
||||
/// templated in order to avoid instantiating SmallVectorTemplateCommon<T>
|
||||
/// whenever we copy-construct an ArrayRef.
|
||||
template <typename U, typename DummyT>
|
||||
/*implicit*/ ArrayRef(
|
||||
const SmallVectorTemplateCommon<U *, DummyT> &Vec,
|
||||
std::enable_if_t<std::is_convertible<U *const *, T const *>::value> * =
|
||||
nullptr)
|
||||
: Data(Vec.data()), Length(Vec.size()) {}
|
||||
|
||||
/// Construct an ArrayRef<const T*> from std::vector<T*>. This uses SFINAE
|
||||
/// to ensure that only vectors of pointers can be converted.
|
||||
template <typename U, typename A>
|
||||
ArrayRef(const std::vector<U *, A> &Vec,
|
||||
std::enable_if_t<std::is_convertible<U *const *, T const *>::value>
|
||||
* = nullptr)
|
||||
: Data(Vec.data()), Length(Vec.size()) {}
|
||||
|
||||
/// Construct an ArrayRef<T> from iterator_range<U*>. This uses SFINAE
|
||||
/// to ensure that this is only used for iterator ranges over plain pointer
|
||||
/// iterators.
|
||||
|
||||
@@ -8,10 +8,16 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
#ifdef __cpp_lib_span
|
||||
#include <span>
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// Check that the ArrayRef-of-pointer converting constructor only allows adding
|
||||
@@ -406,4 +412,15 @@ TEST(ArrayRefTest, MutableArrayRefDeductionGuides) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
static_assert(std::is_constructible_v<ArrayRef<int>, std::span<const int>>,
|
||||
"should be able to construct ArrayRef from const std::span");
|
||||
static_assert(std::is_constructible_v<std::span<const int>, ArrayRef<int>>,
|
||||
"should be able to construct const std::span from ArrayRef");
|
||||
static_assert(std::is_constructible_v<ArrayRef<int>, std::span<int>>,
|
||||
"should be able to construct ArrayRef from mutable std::span");
|
||||
static_assert(!std::is_constructible_v<std::span<int>, ArrayRef<int>>,
|
||||
"cannot construct mutable std::span from ArrayRef");
|
||||
#endif
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
Reference in New Issue
Block a user