Index: include/llvm/ADT/STLExtras.h =================================================================== --- include/llvm/ADT/STLExtras.h +++ include/llvm/ADT/STLExtras.h @@ -130,6 +130,53 @@ // 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 +805,106 @@ /// 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); + decltype(adl_begin(Range))>::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); + decltype(adl_begin(Range))>::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 +913,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: unittests/ADT/STLExtrasTest.cpp =================================================================== --- unittests/ADT/STLExtrasTest.cpp +++ unittests/ADT/STLExtrasTest.cpp @@ -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 + // work with std::swap which defaults to moving + lhs.swap_val = "lhs"; + rhs.swap_val = "rhs"; + } +} + +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); +} + }