1 //===- lld/unittest/RangeTest.cpp -----------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief range.h unit tests.
13 //===----------------------------------------------------------------------===//
15 #include "gtest/gtest.h"
16 #include "lld/Core/range.h"
20 #include <forward_list>
27 template <typename T, typename U> struct AssertTypesSame;
28 template <typename T> struct AssertTypesSame<T, T> {};
29 #define ASSERT_TYPES_SAME(T, U) AssertTypesSame<T, U>()
36 int *begin(free_begin);
39 auto type_of_forward(T &&t) -> decltype(std::forward<T>(t)) {
40 return std::forward<T>(t);
43 template <typename To> To implicit_cast(To val) { return val; }
46 using namespace lld::detail;
47 ASSERT_TYPES_SAME(begin_result<no_begin>::type, undefined);
48 // This causes clang to segfault.
51 begin_result<decltype(type_of_forward(member_begin()))>::type, int *);
53 ASSERT_TYPES_SAME(begin_result<free_begin>::type, int *);
56 TEST(Range, constructors) {
57 std::vector<int> v(5);
58 std::iota(v.begin(), v.end(), 0);
59 lld::range<std::vector<int>::iterator> r = v;
60 EXPECT_EQ(v.begin(), r.begin());
61 EXPECT_EQ(v.end(), r.end());
63 int arr[] = { 1, 2, 3, 4, 5 };
65 lld::range<int *> r2 = arr;
66 EXPECT_EQ(5, r2.back());
69 TEST(Range, conversion_to_pointer_range) {
70 std::vector<int> v(5);
71 std::iota(v.begin(), v.end(), 0);
72 lld::range<int *> r = v;
73 EXPECT_EQ(&*v.begin(), r.begin());
77 template <typename Iter> void takes_range(lld::range<Iter> r) {
80 EXPECT_EQ(expected++, val);
84 void takes_ptr_range(lld::range<const int *> r) {
87 EXPECT_EQ(expected++, val);
91 TEST(Range, passing) {
92 using lld::make_range;
93 using lld::make_ptr_range;
95 std::iota(l.begin(), l.end(), 0);
96 takes_range(make_range(l));
97 takes_range(make_range(implicit_cast<const std::list<int> &>(l)));
99 std::iota(d.begin(), d.end(), 0);
100 takes_range(make_range(d));
101 takes_range(make_range(implicit_cast<const std::deque<int> &>(d)));
102 std::vector<int> v(5);
103 std::iota(v.begin(), v.end(), 0);
104 takes_range(make_range(v));
105 takes_range(make_range(implicit_cast<const std::vector<int> &>(v)));
107 std::is_same<decltype(make_ptr_range(v)), lld::range<int *>>::value,
108 "make_ptr_range should return a range of pointers");
109 takes_range(make_ptr_range(v));
110 takes_range(make_ptr_range(implicit_cast<const std::vector<int> &>(v)));
111 int arr[] = { 0, 1, 2, 3, 4 };
112 takes_range(make_range(arr));
113 const int carr[] = { 0, 1, 2, 3, 4 };
114 takes_range(make_range(carr));
117 takes_ptr_range(implicit_cast<const std::vector<int> &>(v));
118 takes_ptr_range(arr);
119 takes_ptr_range(carr);
122 TEST(Range, access) {
123 std::array<int, 5> a = { { 1, 2, 3, 4, 5 } };
124 lld::range<decltype(a.begin())> r = a;
129 template <bool b> struct CompileAssert;
130 template <> struct CompileAssert<true> {};
132 #if __has_feature(cxx_constexpr)
133 constexpr int arr[] = { 1, 2, 3, 4, 5 };
134 TEST(Range, constexpr) {
135 constexpr lld::range<const int *> r(arr, arr + 5);
136 CompileAssert<r.front() == 1>();
137 CompileAssert<r.size() == 5>();
138 CompileAssert<r[4] == 5>();
142 template <typename Container> void test_slice() {
144 std::iota(cont.begin(), cont.end(), 0);
145 lld::range<decltype(cont.begin())> r = cont;
148 EXPECT_EQ(10, r.slice(0).size());
149 EXPECT_EQ(8, r.slice(2).size());
150 EXPECT_EQ(2, r.slice(2).front());
151 EXPECT_EQ(1, r.slice(-1).size());
152 EXPECT_EQ(9, r.slice(-1).front());
154 // Two positive arguments.
155 EXPECT_TRUE(r.slice(5, 2).empty());
156 EXPECT_EQ(next(cont.begin(), 5), r.slice(5, 2).begin());
157 EXPECT_EQ(1, r.slice(1, 2).size());
158 EXPECT_EQ(1, r.slice(1, 2).front());
160 // Two negative arguments.
161 EXPECT_TRUE(r.slice(-2, -5).empty());
162 EXPECT_EQ(next(cont.begin(), 8), r.slice(-2, -5).begin());
163 EXPECT_EQ(1, r.slice(-2, -1).size());
164 EXPECT_EQ(8, r.slice(-2, -1).front());
166 // Positive start, negative stop.
167 EXPECT_EQ(1, r.slice(6, -3).size());
168 EXPECT_EQ(6, r.slice(6, -3).front());
169 EXPECT_TRUE(r.slice(6, -5).empty());
170 EXPECT_EQ(next(cont.begin(), 6), r.slice(6, -5).begin());
172 // Negative start, positive stop.
173 EXPECT_TRUE(r.slice(-3, 6).empty());
174 EXPECT_EQ(next(cont.begin(), 7), r.slice(-3, 6).begin());
175 EXPECT_EQ(1, r.slice(-5, 6).size());
176 EXPECT_EQ(5, r.slice(-5, 6).front());
180 // -fsanitize=undefined complains about this, but only if optimizations are
183 test_slice<std::forward_list<int>>();
185 test_slice<std::list<int>>();
186 // This doesn't build with libstdc++ 4.7
188 test_slice<std::deque<int>>();
192 // This test is flaky and I've yet to pin down why. Changing between
193 // EXPECT_EQ(1, input.front()) and EXPECT_TRUE(input.front() == 1) makes it work
194 // with VS 2012 in Debug mode. Clang on Linux seems to fail with -03 and -02 -g
195 // -fsanitize=undefined.
197 TEST(Range, istream_range) {
198 std::istringstream stream("1 2 3 4 5");
199 // MSVC interprets input as a function declaration if you don't declare start
200 // and instead directly pass std::istream_iterator<int>(stream).
201 auto start = std::istream_iterator<int>(stream);
202 lld::range<std::istream_iterator<int>> input(
203 start, std::istream_iterator<int>());
204 EXPECT_TRUE(input.front() == 1);
206 EXPECT_TRUE(input.front() == 2);
208 EXPECT_TRUE(input.front() == 4);
209 input.pop_front_upto(7);
210 EXPECT_TRUE(input.empty());
214 //! [algorithm using range]
215 template <typename T> void partial_sum(T &container) {
216 using lld::make_range;
217 auto range = make_range(container);
218 typename T::value_type sum = 0;
219 // One would actually use a range-based for loop
220 // in this case, but you get the idea:
221 for (; !range.empty(); range.pop_front()) {
222 sum += range.front();
228 std::vector<int> v(5, 2);
232 //! [algorithm using range]
234 //! [algorithm using ptr_range]
235 void my_write(int fd, lld::range<const char *> buffer) {}
238 std::string s("Hello world");