//===- lld/unittest/RangeTest.cpp -----------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief range.h unit tests. /// //===----------------------------------------------------------------------===// #include "gtest/gtest.h" #include "lld/Core/range.h" #include #include #include #include #include #include #include #include #include template struct AssertTypesSame; template struct AssertTypesSame {}; #define ASSERT_TYPES_SAME(T, U) AssertTypesSame() struct no_begin {}; struct member_begin { int *begin(); }; struct free_begin {}; int *begin(free_begin); template auto type_of_forward(T &&t) -> decltype(std::forward(t)) { return std::forward(t); } template To implicit_cast(To val) { return val; } void test_traits() { using namespace lld::detail; ASSERT_TYPES_SAME(begin_result::type, undefined); // This causes clang to segfault. #if 0 ASSERT_TYPES_SAME( begin_result::type, int *); #endif ASSERT_TYPES_SAME(begin_result::type, int *); } TEST(Range, constructors) { std::vector v(5); std::iota(v.begin(), v.end(), 0); lld::range::iterator> r = v; EXPECT_EQ(v.begin(), r.begin()); EXPECT_EQ(v.end(), r.end()); int arr[] = { 1, 2, 3, 4, 5 }; std::begin(arr); lld::range r2 = arr; EXPECT_EQ(5, r2.back()); } TEST(Range, conversion_to_pointer_range) { std::vector v(5); std::iota(v.begin(), v.end(), 0); lld::range r = v; EXPECT_EQ(&*v.begin(), r.begin()); EXPECT_EQ(2, r[2]); } template void takes_range(lld::range r) { int expected = 0; for (int val : r) { EXPECT_EQ(expected++, val); } } void takes_ptr_range(lld::range r) { int expected = 0; for (int val : r) { EXPECT_EQ(expected++, val); } } TEST(Range, passing) { using lld::make_range; using lld::make_ptr_range; std::list l(5); std::iota(l.begin(), l.end(), 0); takes_range(make_range(l)); takes_range(make_range(implicit_cast &>(l))); std::deque d(5); std::iota(d.begin(), d.end(), 0); takes_range(make_range(d)); takes_range(make_range(implicit_cast &>(d))); std::vector v(5); std::iota(v.begin(), v.end(), 0); takes_range(make_range(v)); takes_range(make_range(implicit_cast &>(v))); // MSVC Can't compile make_ptr_range. #ifndef _MSC_VER static_assert( std::is_same>::value, "make_ptr_range should return a range of pointers"); takes_range(make_ptr_range(v)); takes_range(make_ptr_range(implicit_cast &>(v))); #endif int arr[] = { 0, 1, 2, 3, 4 }; takes_range(make_range(arr)); const int carr[] = { 0, 1, 2, 3, 4 }; takes_range(make_range(carr)); takes_ptr_range(v); takes_ptr_range(implicit_cast &>(v)); takes_ptr_range(arr); takes_ptr_range(carr); } TEST(Range, access) { std::array a = { { 1, 2, 3, 4, 5 } }; lld::range r = a; EXPECT_EQ(4, r[3]); EXPECT_EQ(4, r[-2]); } template struct CompileAssert; template <> struct CompileAssert {}; #if __has_feature(cxx_constexpr) constexpr int arr[] = { 1, 2, 3, 4, 5 }; TEST(Range, constexpr) { constexpr lld::range r(arr, arr + 5); CompileAssert(); CompileAssert(); CompileAssert(); } #endif template void test_slice() { Container cont(10); std::iota(cont.begin(), cont.end(), 0); lld::range r = cont; // One argument. EXPECT_EQ(10, r.slice(0).size()); EXPECT_EQ(8, r.slice(2).size()); EXPECT_EQ(2, r.slice(2).front()); EXPECT_EQ(1, r.slice(-1).size()); EXPECT_EQ(9, r.slice(-1).front()); // Two positive arguments. EXPECT_TRUE(r.slice(5, 2).empty()); EXPECT_EQ(next(cont.begin(), 5), r.slice(5, 2).begin()); EXPECT_EQ(1, r.slice(1, 2).size()); EXPECT_EQ(1, r.slice(1, 2).front()); // Two negative arguments. EXPECT_TRUE(r.slice(-2, -5).empty()); EXPECT_EQ(next(cont.begin(), 8), r.slice(-2, -5).begin()); EXPECT_EQ(1, r.slice(-2, -1).size()); EXPECT_EQ(8, r.slice(-2, -1).front()); // Positive start, negative stop. EXPECT_EQ(1, r.slice(6, -3).size()); EXPECT_EQ(6, r.slice(6, -3).front()); EXPECT_TRUE(r.slice(6, -5).empty()); EXPECT_EQ(next(cont.begin(), 6), r.slice(6, -5).begin()); // Negative start, positive stop. EXPECT_TRUE(r.slice(-3, 6).empty()); EXPECT_EQ(next(cont.begin(), 7), r.slice(-3, 6).begin()); EXPECT_EQ(1, r.slice(-5, 6).size()); EXPECT_EQ(5, r.slice(-5, 6).front()); } TEST(Range, slice) { // -fsanitize=undefined complains about this, but only if optimizations are // enabled. #if 0 test_slice>(); #endif test_slice>(); // This doesn't build with libstdc++ 4.7 #if 0 test_slice>(); #endif } // This test is flaky and I've yet to pin down why. Changing between // EXPECT_EQ(1, input.front()) and EXPECT_TRUE(input.front() == 1) makes it work // with VS 2012 in Debug mode. Clang on Linux seems to fail with -03 and -02 -g // -fsanitize=undefined. #if 0 TEST(Range, istream_range) { std::istringstream stream("1 2 3 4 5"); // MSVC interprets input as a function declaration if you don't declare start // and instead directly pass std::istream_iterator(stream). auto start = std::istream_iterator(stream); lld::range> input( start, std::istream_iterator()); EXPECT_TRUE(input.front() == 1); input.pop_front(); EXPECT_TRUE(input.front() == 2); input.pop_front(2); EXPECT_TRUE(input.front() == 4); input.pop_front_upto(7); EXPECT_TRUE(input.empty()); } #endif //! [algorithm using range] template void partial_sum(T &container) { using lld::make_range; auto range = make_range(container); typename T::value_type sum = 0; // One would actually use a range-based for loop // in this case, but you get the idea: for (; !range.empty(); range.pop_front()) { sum += range.front(); range.front() = sum; } } TEST(Range, user1) { std::vector v(5, 2); partial_sum(v); EXPECT_EQ(8, v[3]); } //! [algorithm using range] //! [algorithm using ptr_range] void my_write(int fd, lld::range buffer) {} TEST(Range, user2) { std::string s("Hello world"); my_write(1, s); }