Skip to content

Commit 0556a2a

Browse files
authored
[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.
1 parent df79c40 commit 0556a2a

File tree

2 files changed

+31
-39
lines changed

2 files changed

+31
-39
lines changed

llvm/include/llvm/ADT/ArrayRef.h

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,19 @@ namespace llvm {
8484
assert(begin <= end);
8585
}
8686

87-
/// Construct an ArrayRef from a SmallVector. This is templated in order to
88-
/// avoid instantiating SmallVectorTemplateCommon<T> whenever we
89-
/// copy-construct an ArrayRef.
90-
template<typename U>
91-
/*implicit*/ ArrayRef(const SmallVectorTemplateCommon<T, U> &Vec)
92-
: Data(Vec.data()), Length(Vec.size()) {
93-
}
94-
95-
/// Construct an ArrayRef from a std::vector.
96-
template<typename A>
97-
/*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
98-
: Data(Vec.data()), Length(Vec.size()) {}
87+
/// Construct an ArrayRef from a type that has a data() method that returns
88+
/// a pointer convertible to const T *.
89+
template <
90+
typename C,
91+
typename = std::enable_if_t<
92+
std::conjunction_v<
93+
std::is_convertible<
94+
decltype(std::declval<const C &>().data()) *,
95+
const T *const *>,
96+
std::is_integral<decltype(std::declval<const C &>().size())>>,
97+
void>>
98+
/*implicit*/ constexpr ArrayRef(const C &V)
99+
: Data(V.data()), Length(V.size()) {}
99100

100101
/// Construct an ArrayRef from a std::array
101102
template <size_t N>
@@ -123,32 +124,6 @@ namespace llvm {
123124
#pragma GCC diagnostic pop
124125
#endif
125126

126-
/// Construct an ArrayRef<const T*> from ArrayRef<T*>. This uses SFINAE to
127-
/// ensure that only ArrayRefs of pointers can be converted.
128-
template <typename U>
129-
ArrayRef(const ArrayRef<U *> &A,
130-
std::enable_if_t<std::is_convertible<U *const *, T const *>::value>
131-
* = nullptr)
132-
: Data(A.data()), Length(A.size()) {}
133-
134-
/// Construct an ArrayRef<const T*> from a SmallVector<T*>. This is
135-
/// templated in order to avoid instantiating SmallVectorTemplateCommon<T>
136-
/// whenever we copy-construct an ArrayRef.
137-
template <typename U, typename DummyT>
138-
/*implicit*/ ArrayRef(
139-
const SmallVectorTemplateCommon<U *, DummyT> &Vec,
140-
std::enable_if_t<std::is_convertible<U *const *, T const *>::value> * =
141-
nullptr)
142-
: Data(Vec.data()), Length(Vec.size()) {}
143-
144-
/// Construct an ArrayRef<const T*> from std::vector<T*>. This uses SFINAE
145-
/// to ensure that only vectors of pointers can be converted.
146-
template <typename U, typename A>
147-
ArrayRef(const std::vector<U *, A> &Vec,
148-
std::enable_if_t<std::is_convertible<U *const *, T const *>::value>
149-
* = nullptr)
150-
: Data(Vec.data()), Length(Vec.size()) {}
151-
152127
/// Construct an ArrayRef<T> from iterator_range<U*>. This uses SFINAE
153128
/// to ensure that this is only used for iterator ranges over plain pointer
154129
/// iterators.

llvm/unittests/ADT/ArrayRefTest.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@
88

99
#include "llvm/ADT/ArrayRef.h"
1010
#include "llvm/Support/Allocator.h"
11-
#include "llvm/Support/raw_ostream.h"
1211
#include "gtest/gtest.h"
1312
#include <limits>
1413
#include <vector>
14+
#if __has_include(<version>)
15+
#include <version>
16+
#endif
17+
#ifdef __cpp_lib_span
18+
#include <span>
19+
#endif
20+
1521
using namespace llvm;
1622

1723
// Check that the ArrayRef-of-pointer converting constructor only allows adding
@@ -406,4 +412,15 @@ TEST(ArrayRefTest, MutableArrayRefDeductionGuides) {
406412
}
407413
}
408414

415+
#ifdef __cpp_lib_span
416+
static_assert(std::is_constructible_v<ArrayRef<int>, std::span<const int>>,
417+
"should be able to construct ArrayRef from const std::span");
418+
static_assert(std::is_constructible_v<std::span<const int>, ArrayRef<int>>,
419+
"should be able to construct const std::span from ArrayRef");
420+
static_assert(std::is_constructible_v<ArrayRef<int>, std::span<int>>,
421+
"should be able to construct ArrayRef from mutable std::span");
422+
static_assert(!std::is_constructible_v<std::span<int>, ArrayRef<int>>,
423+
"cannot construct mutable std::span from ArrayRef");
424+
#endif
425+
409426
} // end anonymous namespace

0 commit comments

Comments
 (0)