Skip to content

Commit ecfb90e

Browse files
fhahnAnkur-0429
authored andcommitted
[ArrayRef] Add constructor from iterator_range<U*> (NFC). (llvm#137796)
Add a new constructor to ArrayRef that takes an iterator_range with a random access iterator that can be converted. This can help to avoid creating unnecessary iterator_ranges for types where an ArrayRef can already be constructed. To be used in llvm#137798. PR: llvm#137796
1 parent 30ed24f commit ecfb90e

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

llvm/include/llvm/ADT/ArrayRef.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ namespace llvm {
149149
* = nullptr)
150150
: Data(Vec.data()), Length(Vec.size()) {}
151151

152+
/// Construct an ArrayRef<T> from iterator_range<U*>. This uses SFINAE
153+
/// to ensure that this is only used for iterator ranges over plain pointer
154+
/// iterators.
155+
template <typename U, typename = std::enable_if_t<
156+
std::is_convertible_v<U *const *, T *const *>>>
157+
ArrayRef(const iterator_range<U *> &Range)
158+
: Data(Range.begin()), Length(llvm::size(Range)) {}
159+
152160
/// @}
153161
/// @name Simple Operations
154162
/// @{

llvm/unittests/ADT/ArrayRefTest.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,64 @@ TEST(ArrayRefTest, ArrayRefFromStdArray) {
255255
}
256256
}
257257

258+
struct TestRandomAccessIterator {
259+
using iterator_category = std::random_access_iterator_tag;
260+
};
261+
262+
static_assert(!std::is_constructible_v<
263+
ArrayRef<int>, iterator_range<TestRandomAccessIterator>>,
264+
"cannot construct from iterator range with non-pointer iterator");
265+
static_assert(!std::is_constructible_v<ArrayRef<int>, iterator_range<int>>,
266+
"cannot construct from iterator range with non-pointer iterator");
267+
268+
class TestBase {};
269+
270+
class TestDerived : public TestBase {};
271+
272+
static_assert(
273+
!std::is_constructible_v<ArrayRef<TestDerived>, iterator_range<TestBase *>>,
274+
"cannot construct ArrayRef with derived type");
275+
static_assert(
276+
!std::is_constructible_v<ArrayRef<TestBase>, iterator_range<TestDerived *>>,
277+
"cannot construct ArrayRef base type");
278+
static_assert(!std::is_constructible_v<ArrayRef<TestBase *>,
279+
iterator_range<TestDerived **>>,
280+
"cannot construct ArrayRef pointer of base type");
281+
282+
static_assert(
283+
!std::is_constructible_v<ArrayRef<int>, iterator_range<const int *>>,
284+
"cannot construct ArrayRef with non-const elements from const iterator "
285+
"range");
286+
static_assert(
287+
std::is_constructible_v<ArrayRef<char *>, iterator_range<char **>>,
288+
"should be able to construct ArrayRef from iterator_range over pointers");
289+
static_assert(
290+
!std::is_constructible_v<ArrayRef<char *>, iterator_range<char *const *>>,
291+
"should be able to construct ArrayRef from iterator_range over pointers");
292+
293+
TEST(ArrayRefTest, ArrayRefFromIteratorRange) {
294+
std::array<int, 5> A1{{42, -5, 0, 1000000, -1000000}};
295+
ArrayRef<int> A2 = make_range(A1.begin(), A1.end());
296+
297+
EXPECT_EQ(A1.size(), A2.size());
298+
for (std::size_t i = 0; i < A1.size(); ++i)
299+
EXPECT_EQ(A1[i], A2[i]);
300+
301+
ArrayRef<const int> A3 = make_range(A1.begin(), A1.end());
302+
EXPECT_EQ(A1.size(), A3.size());
303+
for (std::size_t i = 0; i < A1.size(); ++i)
304+
EXPECT_EQ(A1[i], A3[i]);
305+
}
306+
307+
TEST(ArrayRefTest, ArrayRefFromIteratorConstRange) {
308+
std::array<const int, 5> A1{{42, -5, 0, 1000000, -1000000}};
309+
ArrayRef<const int> A2 = make_range(A1.begin(), A1.end());
310+
311+
EXPECT_EQ(A1.size(), A2.size());
312+
for (std::size_t i = 0; i < A1.size(); ++i)
313+
EXPECT_EQ(A1[i], A2[i]);
314+
}
315+
258316
static_assert(std::is_trivially_copyable_v<ArrayRef<int>>,
259317
"trivially copyable");
260318

0 commit comments

Comments
 (0)