Skip to content

Commit fa404ae

Browse files
committed
[libc] Enhance ArrayRef + unittests
This patch mostly adds unittests for `ArrayRef` and `MutableArrayRef`, additionnaly: - We mimic the behavior of `std::vector` and disallow CV qualified type (`ArrayRef<const X>` is not allowed). This is to make sure that the type traits are always valid (e.g. `value_type`, `pointer`, ...). - In the previous implementation `ArrayRef` would define `value_type` as `const T` but this is not correct, it should be `T` for both `MutableArrayRef` and `ArrayRef`. - We add the `equals` method to ease testing, - We define the constructor taking an `Array` outside of the base implementation to ensure we match `const Array<T>&` and not `Array<const T>&` in the case of `ArrayRef`. Differential Revision: https://reviews.llvm.org/D100732
1 parent ca9b7e2 commit fa404ae

File tree

3 files changed

+300
-32
lines changed

3 files changed

+300
-32
lines changed

libc/test/utils/CPP/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,13 @@ add_libc_unittest(
1919
DEPENDS
2020
libc.utils.CPP.standalone_cpp
2121
)
22+
23+
add_libc_unittest(
24+
arrayref_test
25+
SUITE
26+
libc_cpp_utils_unittests
27+
SRCS
28+
arrayref_test.cpp
29+
DEPENDS
30+
libc.utils.CPP.standalone_cpp
31+
)

libc/test/utils/CPP/arrayref_test.cpp

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
//===-- Unittests for ArrayRef --------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "utils/CPP/ArrayRef.h"
10+
#include "utils/UnitTest/Test.h"
11+
12+
namespace __llvm_libc {
13+
namespace cpp {
14+
15+
// The following tests run on both 'ArrayRef' and 'MutableArrayRef'.
16+
using Types = testing::TypeList<ArrayRef<int>, MutableArrayRef<int>>;
17+
18+
TYPED_TEST(LlvmLibcArrayRefTest, ConstructFromElement, Types) {
19+
using value_type = typename ParamType::value_type;
20+
using const_pointer = typename ParamType::const_pointer;
21+
value_type element = 5;
22+
ParamType arrayref(element);
23+
EXPECT_FALSE(arrayref.empty());
24+
EXPECT_EQ(arrayref.size(), 1UL);
25+
EXPECT_EQ(arrayref[0], 5);
26+
EXPECT_EQ((const_pointer)arrayref.data(), (const_pointer)&element);
27+
}
28+
29+
TYPED_TEST(LlvmLibcArrayRefTest, ConstructFromPointerAndSize, Types) {
30+
using value_type = typename ParamType::value_type;
31+
using const_pointer = typename ParamType::const_pointer;
32+
value_type values[] = {1, 2};
33+
ParamType arrayref(values, 2);
34+
EXPECT_FALSE(arrayref.empty());
35+
EXPECT_EQ(arrayref.size(), 2UL);
36+
EXPECT_EQ(arrayref[0], 1);
37+
EXPECT_EQ(arrayref[1], 2);
38+
EXPECT_EQ((const_pointer)arrayref.data(), (const_pointer)values);
39+
}
40+
41+
TYPED_TEST(LlvmLibcArrayRefTest, ConstructFromIterator, Types) {
42+
using value_type = typename ParamType::value_type;
43+
using const_pointer = typename ParamType::const_pointer;
44+
value_type values[] = {1, 2};
45+
ParamType arrayref(&values[0], &values[2]);
46+
EXPECT_FALSE(arrayref.empty());
47+
EXPECT_EQ(arrayref.size(), 2UL);
48+
EXPECT_EQ(arrayref[0], 1);
49+
EXPECT_EQ(arrayref[1], 2);
50+
EXPECT_EQ((const_pointer)arrayref.data(), (const_pointer)&values[0]);
51+
}
52+
53+
TYPED_TEST(LlvmLibcArrayRefTest, ConstructFromCArray, Types) {
54+
using value_type = typename ParamType::value_type;
55+
using const_pointer = typename ParamType::const_pointer;
56+
value_type values[] = {1, 2};
57+
ParamType arrayref(values);
58+
EXPECT_FALSE(arrayref.empty());
59+
EXPECT_EQ(arrayref.size(), 2UL);
60+
EXPECT_EQ(arrayref[0], 1);
61+
EXPECT_EQ(arrayref[1], 2);
62+
EXPECT_EQ((const_pointer)arrayref.data(), (const_pointer)values);
63+
}
64+
65+
TYPED_TEST(LlvmLibcArrayRefTest, ConstructFromLibcArray, Types) {
66+
using value_type = typename ParamType::value_type;
67+
using const_pointer = typename ParamType::const_pointer;
68+
Array<value_type, 2> values = {1, 2};
69+
ParamType arrayref(values);
70+
EXPECT_FALSE(arrayref.empty());
71+
EXPECT_EQ(arrayref.size(), 2UL);
72+
EXPECT_EQ(arrayref[0], 1);
73+
EXPECT_EQ(arrayref[1], 2);
74+
EXPECT_EQ((const_pointer)arrayref.data(), (const_pointer)values.data());
75+
}
76+
77+
TYPED_TEST(LlvmLibcArrayRefTest, Equals, Types) {
78+
using value_type = typename ParamType::value_type;
79+
value_type values[] = {1, 2, 3};
80+
ParamType initial(values);
81+
EXPECT_TRUE(initial.equals(initial));
82+
ParamType shallow_copy(values);
83+
EXPECT_TRUE(initial.equals(shallow_copy));
84+
value_type same_values[] = {1, 2, 3};
85+
EXPECT_TRUE(initial.equals(same_values));
86+
value_type different_values[] = {1, 2, 4};
87+
EXPECT_FALSE(initial.equals(different_values));
88+
}
89+
90+
TYPED_TEST(LlvmLibcArrayRefTest, SliceUnary, Types) {
91+
using value_type = typename ParamType::value_type;
92+
value_type values[] = {1, 2, 3};
93+
ParamType arrayref(values);
94+
{
95+
value_type values[] = {1, 2, 3};
96+
EXPECT_TRUE(arrayref.slice(0).equals(values));
97+
}
98+
{
99+
value_type values[] = {2, 3};
100+
EXPECT_TRUE(arrayref.slice(1).equals(values));
101+
}
102+
{
103+
value_type values[] = {3};
104+
EXPECT_TRUE(arrayref.slice(2).equals(values));
105+
}
106+
{ EXPECT_TRUE(arrayref.slice(3).empty()); }
107+
}
108+
109+
TYPED_TEST(LlvmLibcArrayRefTest, SliceBinary, Types) {
110+
using value_type = typename ParamType::value_type;
111+
value_type values[] = {1, 2, 3};
112+
ParamType arrayref(values);
113+
{
114+
EXPECT_TRUE(arrayref.slice(0, 0).empty());
115+
EXPECT_TRUE(arrayref.slice(1, 0).empty());
116+
EXPECT_TRUE(arrayref.slice(2, 0).empty());
117+
EXPECT_TRUE(arrayref.slice(3, 0).empty());
118+
}
119+
{
120+
value_type values[] = {1};
121+
EXPECT_TRUE(arrayref.slice(0, 1).equals(values));
122+
}
123+
{
124+
value_type values[] = {2};
125+
EXPECT_TRUE(arrayref.slice(1, 1).equals(values));
126+
}
127+
{
128+
value_type values[] = {3};
129+
EXPECT_TRUE(arrayref.slice(2, 1).equals(values));
130+
}
131+
{
132+
value_type values[] = {1, 2};
133+
EXPECT_TRUE(arrayref.slice(0, 2).equals(values));
134+
}
135+
{
136+
value_type values[] = {2, 3};
137+
EXPECT_TRUE(arrayref.slice(1, 2).equals(values));
138+
}
139+
{
140+
value_type values[] = {1, 2, 3};
141+
EXPECT_TRUE(arrayref.slice(0, 3).equals(values));
142+
}
143+
}
144+
145+
TYPED_TEST(LlvmLibcArrayRefTest, DropFront, Types) {
146+
using value_type = typename ParamType::value_type;
147+
value_type values[] = {1, 2, 3};
148+
ParamType arrayref(values);
149+
{
150+
value_type values[] = {1, 2, 3};
151+
EXPECT_TRUE(arrayref.drop_front(0).equals(values));
152+
}
153+
{
154+
value_type values[] = {2, 3};
155+
EXPECT_TRUE(arrayref.drop_front(1).equals(values));
156+
}
157+
{
158+
value_type values[] = {3};
159+
EXPECT_TRUE(arrayref.drop_front(2).equals(values));
160+
}
161+
{ EXPECT_TRUE(arrayref.drop_front(3).empty()); }
162+
}
163+
164+
TYPED_TEST(LlvmLibcArrayRefTest, DropBack, Types) {
165+
using value_type = typename ParamType::value_type;
166+
value_type values[] = {1, 2, 3};
167+
ParamType arrayref(values);
168+
{
169+
value_type values[] = {1, 2, 3};
170+
EXPECT_TRUE(arrayref.drop_back(0).equals(values));
171+
}
172+
{
173+
value_type values[] = {1, 2};
174+
EXPECT_TRUE(arrayref.drop_back(1).equals(values));
175+
}
176+
{
177+
value_type values[] = {1};
178+
EXPECT_TRUE(arrayref.drop_back(2).equals(values));
179+
}
180+
{ EXPECT_TRUE(arrayref.drop_back(3).empty()); }
181+
}
182+
183+
TYPED_TEST(LlvmLibcArrayRefTest, TakeFront, Types) {
184+
using value_type = typename ParamType::value_type;
185+
value_type values[] = {1, 2, 3};
186+
ParamType arrayref(values);
187+
{ EXPECT_TRUE(arrayref.take_front(0).empty()); }
188+
{
189+
value_type values[] = {1};
190+
EXPECT_TRUE(arrayref.take_front(1).equals(values));
191+
}
192+
{
193+
value_type values[] = {1, 2};
194+
EXPECT_TRUE(arrayref.take_front(2).equals(values));
195+
}
196+
{
197+
value_type values[] = {1, 2, 3};
198+
EXPECT_TRUE(arrayref.take_front(3).equals(values));
199+
}
200+
}
201+
202+
TYPED_TEST(LlvmLibcArrayRefTest, TakeBack, Types) {
203+
using value_type = typename ParamType::value_type;
204+
value_type values[] = {1, 2, 3};
205+
ParamType arrayref(values);
206+
{ EXPECT_TRUE(arrayref.take_back(0).empty()); }
207+
{
208+
value_type values[] = {3};
209+
EXPECT_TRUE(arrayref.take_back(1).equals(values));
210+
}
211+
{
212+
value_type values[] = {2, 3};
213+
EXPECT_TRUE(arrayref.take_back(2).equals(values));
214+
}
215+
{
216+
value_type values[] = {1, 2, 3};
217+
EXPECT_TRUE(arrayref.take_back(3).equals(values));
218+
}
219+
}
220+
221+
} // namespace cpp
222+
} // namespace __llvm_libc

libc/utils/CPP/ArrayRef.h

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLVM_LIBC_UTILS_CPP_ARRAYREF_H
1111

1212
#include "Array.h"
13+
#include "TypeTraits.h" //RemoveCVType
1314

1415
#include <stddef.h> // For size_t.
1516

@@ -21,81 +22,116 @@ namespace cpp {
2122
// llvm/ADT/ArrayRef.h. The implementations in this file are of a limited
2223
// functionality, but can be extended in an as needed basis.
2324
namespace internal {
24-
template <typename T> class ArrayRefBase {
25+
template <typename QualifiedT> class ArrayRefBase {
2526
public:
26-
using iterator = T *;
27-
using pointer = T *;
28-
using reference = T &;
27+
using value_type = RemoveCVType<QualifiedT>;
28+
using pointer = value_type *;
29+
using const_pointer = const value_type *;
30+
using reference = value_type &;
31+
using const_reference = const value_type &;
32+
using iterator = const_pointer;
33+
using const_iterator = const_pointer;
34+
using size_type = size_t;
35+
using difference_type = ptrdiff_t;
2936

3037
ArrayRefBase() = default;
3138

32-
// From Array.
33-
template <size_t N>
34-
ArrayRefBase(Array<T, N> &Arr) : Data(Arr.Data), Length(N) {}
35-
3639
// Construct an ArrayRefBase from a single element.
37-
explicit ArrayRefBase(T &OneElt) : Data(&OneElt), Length(1) {}
40+
explicit ArrayRefBase(QualifiedT &OneElt) : Data(&OneElt), Length(1) {}
3841

3942
// Construct an ArrayRefBase from a pointer and length.
40-
ArrayRefBase(pointer Data, size_t Length) : Data(Data), Length(Length) {}
43+
ArrayRefBase(QualifiedT *Data, size_t Length) : Data(Data), Length(Length) {}
4144

4245
// Construct an ArrayRefBase from a range.
43-
ArrayRefBase(iterator Begin, iterator End)
46+
ArrayRefBase(QualifiedT *Begin, QualifiedT *End)
4447
: Data(Begin), Length(End - Begin) {}
4548

4649
// Construct an ArrayRefBase from a C array.
4750
template <size_t N>
48-
constexpr ArrayRefBase(T (&Arr)[N]) : Data(Arr), Length(N) {}
51+
constexpr ArrayRefBase(QualifiedT (&Arr)[N]) : Data(Arr), Length(N) {}
4952

50-
iterator begin() const { return Data; }
51-
iterator end() const { return Data + Length; }
52-
53-
bool empty() const { return Length == 0; }
53+
QualifiedT *data() const { return Data; }
54+
size_t size() const { return Length; }
5455

55-
pointer data() const { return Data; }
56+
auto begin() const { return data(); }
57+
auto end() const { return data() + size(); }
5658

57-
size_t size() const { return Length; }
59+
bool empty() const { return size() == 0; }
5860

59-
reference operator[](size_t Index) const { return Data[Index]; }
61+
auto operator[](size_t Index) const { return data()[Index]; }
6062

6163
// slice(n, m) - Chop off the first N elements of the array, and keep M
6264
// elements in the array.
63-
ArrayRefBase<T> slice(size_t N, size_t M) const {
64-
return ArrayRefBase<T>(data() + N, M);
65-
}
65+
auto slice(size_t N, size_t M) const { return ArrayRefBase(data() + N, M); }
6666
// slice(n) - Chop off the first N elements of the array.
67-
ArrayRefBase<T> slice(size_t N) const { return slice(N, size() - N); }
67+
auto slice(size_t N) const { return slice(N, size() - N); }
6868

6969
// Drop the first \p N elements of the array.
70-
ArrayRefBase<T> drop_front(size_t N = 1) const {
71-
return slice(N, size() - N);
72-
}
70+
auto drop_front(size_t N = 1) const { return slice(N, size() - N); }
7371

7472
// Drop the last \p N elements of the array.
75-
ArrayRefBase<T> drop_back(size_t N = 1) const { return slice(0, size() - N); }
73+
auto drop_back(size_t N = 1) const { return slice(0, size() - N); }
7674

7775
// Return a copy of *this with only the first \p N elements.
78-
ArrayRefBase<T> take_front(size_t N = 1) const {
76+
auto take_front(size_t N = 1) const {
7977
if (N >= size())
8078
return *this;
8179
return drop_back(size() - N);
8280
}
8381

8482
// Return a copy of *this with only the last \p N elements.
85-
ArrayRefBase<T> take_back(size_t N = 1) const {
83+
auto take_back(size_t N = 1) const {
8684
if (N >= size())
8785
return *this;
8886
return drop_front(size() - N);
8987
}
9088

89+
// equals - Check for element-wise equality.
90+
bool equals(ArrayRefBase<QualifiedT> RHS) const {
91+
if (Length != RHS.Length)
92+
return false;
93+
auto First1 = begin();
94+
auto Last1 = end();
95+
auto First2 = RHS.begin();
96+
for (; First1 != Last1; ++First1, ++First2) {
97+
if (!(*First1 == *First2)) {
98+
return false;
99+
}
100+
}
101+
return true;
102+
}
103+
91104
private:
92-
pointer Data = nullptr;
105+
QualifiedT *Data = nullptr;
93106
size_t Length = 0;
94107
};
95108
} // namespace internal
96109

97-
template <typename T> using ArrayRef = internal::ArrayRefBase<const T>;
98-
template <typename T> using MutableArrayRef = internal::ArrayRefBase<T>;
110+
template <typename T> struct ArrayRef : public internal::ArrayRefBase<const T> {
111+
private:
112+
static_assert(IsSameV<T, RemoveCVType<T>>,
113+
"ArrayRef must have a non-const, non-volatile value_type");
114+
using Impl = internal::ArrayRefBase<const T>;
115+
using Impl::Impl;
116+
117+
public:
118+
// From Array.
119+
template <size_t N> ArrayRef(const Array<T, N> &Arr) : Impl(Arr.Data, N) {}
120+
};
121+
122+
template <typename T>
123+
struct MutableArrayRef : public internal::ArrayRefBase<T> {
124+
private:
125+
static_assert(
126+
IsSameV<T, RemoveCVType<T>>,
127+
"MutableArrayRef must have a non-const, non-volatile value_type");
128+
using Impl = internal::ArrayRefBase<T>;
129+
using Impl::Impl;
130+
131+
public:
132+
// From Array.
133+
template <size_t N> MutableArrayRef(Array<T, N> &Arr) : Impl(Arr.Data, N) {}
134+
};
99135

100136
} // namespace cpp
101137
} // namespace __llvm_libc

0 commit comments

Comments
 (0)