Index: llvm/trunk/include/llvm/ADT/STLExtras.h =================================================================== --- llvm/trunk/include/llvm/ADT/STLExtras.h +++ llvm/trunk/include/llvm/ADT/STLExtras.h @@ -130,6 +130,52 @@ // Extra additions to //===----------------------------------------------------------------------===// +namespace adl_detail { + +using std::begin; + +template +auto adl_begin(ContainerTy &&container) + -> decltype(begin(std::forward(container))) { + return begin(std::forward(container)); +} + +using std::end; + +template +auto adl_end(ContainerTy &&container) + -> decltype(end(std::forward(container))) { + return end(std::forward(container)); +} + +using std::swap; + +template +void adl_swap(T &&lhs, T &&rhs) noexcept(noexcept(swap(std::declval(), + std::declval()))) { + swap(std::forward(lhs), std::forward(rhs)); +} + +} // end namespace adl_detail + +template +auto adl_begin(ContainerTy &&container) + -> decltype(adl_detail::adl_begin(std::forward(container))) { + return adl_detail::adl_begin(std::forward(container)); +} + +template +auto adl_end(ContainerTy &&container) + -> decltype(adl_detail::adl_end(std::forward(container))) { + return adl_detail::adl_end(std::forward(container)); +} + +template +void adl_swap(T &&lhs, T &&rhs) noexcept( + noexcept(adl_detail::adl_swap(std::declval(), std::declval()))) { + adl_detail::adl_swap(std::forward(lhs), std::forward(rhs)); +} + // mapped_iterator - This is a simple iterator adapter that causes a function to // be applied whenever operator* is invoked on the iterator. @@ -758,106 +804,105 @@ /// pass begin/end explicitly. template UnaryPredicate for_each(R &&Range, UnaryPredicate P) { - return std::for_each(std::begin(Range), std::end(Range), P); + return std::for_each(adl_begin(Range), adl_end(Range), P); } /// Provide wrappers to std::all_of which take ranges instead of having to pass /// begin/end explicitly. template bool all_of(R &&Range, UnaryPredicate P) { - return std::all_of(std::begin(Range), std::end(Range), P); + return std::all_of(adl_begin(Range), adl_end(Range), P); } /// Provide wrappers to std::any_of which take ranges instead of having to pass /// begin/end explicitly. template bool any_of(R &&Range, UnaryPredicate P) { - return std::any_of(std::begin(Range), std::end(Range), P); + return std::any_of(adl_begin(Range), adl_end(Range), P); } /// Provide wrappers to std::none_of which take ranges instead of having to pass /// begin/end explicitly. template bool none_of(R &&Range, UnaryPredicate P) { - return std::none_of(std::begin(Range), std::end(Range), P); + return std::none_of(adl_begin(Range), adl_end(Range), P); } /// Provide wrappers to std::find which take ranges instead of having to pass /// begin/end explicitly. template -auto find(R &&Range, const T &Val) -> decltype(std::begin(Range)) { - return std::find(std::begin(Range), std::end(Range), Val); +auto find(R &&Range, const T &Val) -> decltype(adl_begin(Range)) { + return std::find(adl_begin(Range), adl_end(Range), Val); } /// Provide wrappers to std::find_if which take ranges instead of having to pass /// begin/end explicitly. template -auto find_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) { - return std::find_if(std::begin(Range), std::end(Range), P); +auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) { + return std::find_if(adl_begin(Range), adl_end(Range), P); } template -auto find_if_not(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) { - return std::find_if_not(std::begin(Range), std::end(Range), P); +auto find_if_not(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) { + return std::find_if_not(adl_begin(Range), adl_end(Range), P); } /// Provide wrappers to std::remove_if which take ranges instead of having to /// pass begin/end explicitly. template -auto remove_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) { - return std::remove_if(std::begin(Range), std::end(Range), P); +auto remove_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) { + return std::remove_if(adl_begin(Range), adl_end(Range), P); } /// Provide wrappers to std::copy_if which take ranges instead of having to /// pass begin/end explicitly. template OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P) { - return std::copy_if(std::begin(Range), std::end(Range), Out, P); + return std::copy_if(adl_begin(Range), adl_end(Range), Out, P); } /// Wrapper function around std::find to detect if an element exists /// in a container. template bool is_contained(R &&Range, const E &Element) { - return std::find(std::begin(Range), std::end(Range), Element) != - std::end(Range); + return std::find(adl_begin(Range), adl_end(Range), Element) != adl_end(Range); } /// Wrapper function around std::count to count the number of times an element /// \p Element occurs in the given range \p Range. template -auto count(R &&Range, const E &Element) -> typename std::iterator_traits< - decltype(std::begin(Range))>::difference_type { - return std::count(std::begin(Range), std::end(Range), Element); +auto count(R &&Range, const E &Element) -> + typename std::iterator_traits::difference_type { + return std::count(adl_begin(Range), adl_end(Range), Element); } /// Wrapper function around std::count_if to count the number of times an /// element satisfying a given predicate occurs in a range. template -auto count_if(R &&Range, UnaryPredicate P) -> typename std::iterator_traits< - decltype(std::begin(Range))>::difference_type { - return std::count_if(std::begin(Range), std::end(Range), P); +auto count_if(R &&Range, UnaryPredicate P) -> + typename std::iterator_traits::difference_type { + return std::count_if(adl_begin(Range), adl_end(Range), P); } /// Wrapper function around std::transform to apply a function to a range and /// store the result elsewhere. template OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate P) { - return std::transform(std::begin(Range), std::end(Range), d_first, P); + return std::transform(adl_begin(Range), adl_end(Range), d_first, P); } /// Provide wrappers to std::partition which take ranges instead of having to /// pass begin/end explicitly. template -auto partition(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) { - return std::partition(std::begin(Range), std::end(Range), P); +auto partition(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) { + return std::partition(adl_begin(Range), adl_end(Range), P); } /// Provide wrappers to std::lower_bound which take ranges instead of having to /// pass begin/end explicitly. template -auto lower_bound(R &&Range, ForwardIt I) -> decltype(std::begin(Range)) { - return std::lower_bound(std::begin(Range), std::end(Range), I); +auto lower_bound(R &&Range, ForwardIt I) -> decltype(adl_begin(Range)) { + return std::lower_bound(adl_begin(Range), adl_end(Range), I); } /// \brief Given a range of type R, iterate the entire range and return a @@ -866,7 +911,7 @@ template SmallVector>::type, Size> to_vector(R &&Range) { - return {std::begin(Range), std::end(Range)}; + return {adl_begin(Range), adl_end(Range)}; } /// Provide a container algorithm similar to C++ Library Fundamentals v2's Index: llvm/trunk/unittests/ADT/STLExtrasTest.cpp =================================================================== --- llvm/trunk/unittests/ADT/STLExtrasTest.cpp +++ llvm/trunk/unittests/ADT/STLExtrasTest.cpp @@ -252,20 +252,20 @@ EXPECT_EQ(3, count(v, 1)); EXPECT_EQ(2, count(v, 2)); EXPECT_EQ(1, count(v, 3)); - EXPECT_EQ(1, count(v, 4)); -} - -TEST(STLExtrasTest, for_each) { - std::vector v{ 0, 1, 2, 3, 4 }; - int count = 0; - - llvm::for_each(v, [&count](int) { ++count; }); - EXPECT_EQ(5, count); -} - -TEST(STLExtrasTest, ToVector) { - std::vector v = {'a', 'b', 'c'}; - auto Enumerated = to_vector<4>(enumerate(v)); + EXPECT_EQ(1, count(v, 4)); +} + +TEST(STLExtrasTest, for_each) { + std::vector v{0, 1, 2, 3, 4}; + int count = 0; + + llvm::for_each(v, [&count](int) { ++count; }); + EXPECT_EQ(5, count); +} + +TEST(STLExtrasTest, ToVector) { + std::vector v = {'a', 'b', 'c'}; + auto Enumerated = to_vector<4>(enumerate(v)); ASSERT_EQ(3u, Enumerated.size()); for (size_t I = 0; I < v.size(); ++I) { EXPECT_EQ(I, Enumerated[I].index()); @@ -326,4 +326,42 @@ EXPECT_EQ(7, V[3]); } +namespace some_namespace { +struct some_struct { + std::vector data; + std::string swap_val; +}; + +std::vector::const_iterator begin(const some_struct &s) { + return s.data.begin(); +} + +std::vector::const_iterator end(const some_struct &s) { + return s.data.end(); } + +void swap(some_struct &lhs, some_struct &rhs) { + // make swap visible as non-adl swap would even seem to + // work with std::swap which defaults to moving + lhs.swap_val = "lhs"; + rhs.swap_val = "rhs"; +} +} // namespace some_namespace + +TEST(STLExtrasTest, ADLTest) { + some_namespace::some_struct s{{1, 2, 3, 4, 5}, ""}; + some_namespace::some_struct s2{{2, 4, 6, 8, 10}, ""}; + + EXPECT_EQ(*adl_begin(s), 1); + EXPECT_EQ(*(adl_end(s) - 1), 5); + + adl_swap(s, s2); + EXPECT_EQ(s.swap_val, "lhs"); + EXPECT_EQ(s2.swap_val, "rhs"); + + int count = 0; + llvm::for_each(s, [&count](int) { ++count; }); + EXPECT_EQ(5, count); +} + +} // namespace