Index: include/llvm/ADT/STLExtras.h =================================================================== --- include/llvm/ADT/STLExtras.h +++ include/llvm/ADT/STLExtras.h @@ -130,6 +130,42 @@ // Extra additions to //===----------------------------------------------------------------------===// +namespace adl { + +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)); +} + +} // end namespace adl_detail + +template +auto begin(ContainerTy &&container) + -> decltype(adl_detail::adl_begin(std::forward(container))) { + return adl_detail::adl_begin(std::forward(container)); +} + +template +auto end(ContainerTy &&container) + -> decltype(adl_detail::adl_end(std::forward(container))) { + return adl_detail::adl_end(std::forward(container)); +} + +} // end namespace adl + // mapped_iterator - This is a simple iterator adapter that causes a function to // be applied whenever operator* is invoked on the iterator. template @@ -817,106 +853,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 @@ -925,7 +961,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,29 @@ EXPECT_EQ(7, V[3]); } +namespace some_namespace { + struct some_struct { + std::vector data; + }; + + 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(); + } +} + +TEST(STLExtrasTest, ADLBeginEnd) { + some_namespace::some_struct s{{ 1, 2, 3, 4, 5 }}; + + EXPECT_EQ(*adl::begin(s), 1); + EXPECT_EQ(*(adl::end(s) - 1), 5); + + int count = 0; + llvm::for_each(s, [&count](int) { ++count; }); + EXPECT_EQ(5, count); +} + }