llvm.org GIT mirror llvm / 3f395b6
Add ADL support to range based <algorithm> extensions This adds support for ADL in the range based <algorithm> extensions (llvm::for_each etc.). Also adds the helper functions llvm::adl::begin and llvm::adl::end which wrap std::begin and std::end with ADL support. Saw this was missing from a recent llvm weekly post about adding llvm::for_each and thought I might add it. Patch by Stephen Dollberg! Differential Revision: https://reviews.llvm.org/D40006 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@318703 91177308-0d34-0410-b5e6-96231b3b80d8 David Blaikie 1 year, 11 months ago
2 changed file(s) with 125 addition(s) and 42 deletion(s). Raw diff Collapse all Expand all
128128 //===----------------------------------------------------------------------===//
129129 // Extra additions to
130130 //===----------------------------------------------------------------------===//
131
132 namespace adl_detail {
133
134 using std::begin;
135
136 template
137 auto adl_begin(ContainerTy &&container)
138 -> decltype(begin(std::forward(container))) {
139 return begin(std::forward(container));
140 }
141
142 using std::end;
143
144 template
145 auto adl_end(ContainerTy &&container)
146 -> decltype(end(std::forward(container))) {
147 return end(std::forward(container));
148 }
149
150 using std::swap;
151
152 template
153 void adl_swap(T &&lhs, T &&rhs) noexcept(noexcept(swap(std::declval(),
154 std::declval()))) {
155 swap(std::forward(lhs), std::forward(rhs));
156 }
157
158 } // end namespace adl_detail
159
160 template
161 auto adl_begin(ContainerTy &&container)
162 -> decltype(adl_detail::adl_begin(std::forward(container))) {
163 return adl_detail::adl_begin(std::forward(container));
164 }
165
166 template
167 auto adl_end(ContainerTy &&container)
168 -> decltype(adl_detail::adl_end(std::forward(container))) {
169 return adl_detail::adl_end(std::forward(container));
170 }
171
172 template
173 void adl_swap(T &&lhs, T &&rhs) noexcept(
174 noexcept(adl_detail::adl_swap(std::declval(), std::declval()))) {
175 adl_detail::adl_swap(std::forward(lhs), std::forward(rhs));
176 }
131177
132178 // mapped_iterator - This is a simple iterator adapter that causes a function to
133179 // be applied whenever operator* is invoked on the iterator.
757803 /// pass begin/end explicitly.
758804 template
759805 UnaryPredicate for_each(R &&Range, UnaryPredicate P) {
760 return std::for_each(std::begin(Range), std::end(Range), P);
806 return std::for_each(adl_begin(Range), adl_end(Range), P);
761807 }
762808
763809 /// Provide wrappers to std::all_of which take ranges instead of having to pass
764810 /// begin/end explicitly.
765811 template
766812 bool all_of(R &&Range, UnaryPredicate P) {
767 return std::all_of(std::begin(Range), std::end(Range), P);
813 return std::all_of(adl_begin(Range), adl_end(Range), P);
768814 }
769815
770816 /// Provide wrappers to std::any_of which take ranges instead of having to pass
771817 /// begin/end explicitly.
772818 template
773819 bool any_of(R &&Range, UnaryPredicate P) {
774 return std::any_of(std::begin(Range), std::end(Range), P);
820 return std::any_of(adl_begin(Range), adl_end(Range), P);
775821 }
776822
777823 /// Provide wrappers to std::none_of which take ranges instead of having to pass
778824 /// begin/end explicitly.
779825 template
780826 bool none_of(R &&Range, UnaryPredicate P) {
781 return std::none_of(std::begin(Range), std::end(Range), P);
827 return std::none_of(adl_begin(Range), adl_end(Range), P);
782828 }
783829
784830 /// Provide wrappers to std::find which take ranges instead of having to pass
785831 /// begin/end explicitly.
786832 template
787 auto find(R &&Range, const T &Val) -> decltype(std::begin(Range)) {
788 return std::find(std::begin(Range), std::end(Range), Val);
833 auto find(R &&Range, const T &Val) -> decltype(adl_begin(Range)) {
834 return std::find(adl_begin(Range), adl_end(Range), Val);
789835 }
790836
791837 /// Provide wrappers to std::find_if which take ranges instead of having to pass
792838 /// begin/end explicitly.
793839 template
794 auto find_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
795 return std::find_if(std::begin(Range), std::end(Range), P);
840 auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
841 return std::find_if(adl_begin(Range), adl_end(Range), P);
796842 }
797843
798844 template
799 auto find_if_not(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
800 return std::find_if_not(std::begin(Range), std::end(Range), P);
845 auto find_if_not(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
846 return std::find_if_not(adl_begin(Range), adl_end(Range), P);
801847 }
802848
803849 /// Provide wrappers to std::remove_if which take ranges instead of having to
804850 /// pass begin/end explicitly.
805851 template
806 auto remove_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
807 return std::remove_if(std::begin(Range), std::end(Range), P);
852 auto remove_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
853 return std::remove_if(adl_begin(Range), adl_end(Range), P);
808854 }
809855
810856 /// Provide wrappers to std::copy_if which take ranges instead of having to
811857 /// pass begin/end explicitly.
812858 template
813859 OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P) {
814 return std::copy_if(std::begin(Range), std::end(Range), Out, P);
860 return std::copy_if(adl_begin(Range), adl_end(Range), Out, P);
815861 }
816862
817863 /// Wrapper function around std::find to detect if an element exists
818864 /// in a container.
819865 template
820866 bool is_contained(R &&Range, const E &Element) {
821 return std::find(std::begin(Range), std::end(Range), Element) !=
822 std::end(Range);
867 return std::find(adl_begin(Range), adl_end(Range), Element) != adl_end(Range);
823868 }
824869
825870 /// Wrapper function around std::count to count the number of times an element
826871 /// \p Element occurs in the given range \p Range.
827872 template
828 auto count(R &&Range, const E &Element) -> typename std::iterator_traits<
829 decltype(std::begin(Range))>::difference_type {
830 return std::count(std::begin(Range), std::end(Range), Element);
873 auto count(R &&Range, const E &Element) ->
874 typename std::iterator_traits::difference_type {
875 return std::count(adl_begin(Range), adl_end(Range), Element);
831876 }
832877
833878 /// Wrapper function around std::count_if to count the number of times an
834879 /// element satisfying a given predicate occurs in a range.
835880 template
836 auto count_if(R &&Range, UnaryPredicate P) -> typename std::iterator_traits<
837 decltype(std::begin(Range))>::difference_type {
838 return std::count_if(std::begin(Range), std::end(Range), P);
881 auto count_if(R &&Range, UnaryPredicate P) ->
882 typename std::iterator_traits::difference_type {
883 return std::count_if(adl_begin(Range), adl_end(Range), P);
839884 }
840885
841886 /// Wrapper function around std::transform to apply a function to a range and
842887 /// store the result elsewhere.
843888 template
844889 OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate P) {
845 return std::transform(std::begin(Range), std::end(Range), d_first, P);
890 return std::transform(adl_begin(Range), adl_end(Range), d_first, P);
846891 }
847892
848893 /// Provide wrappers to std::partition which take ranges instead of having to
849894 /// pass begin/end explicitly.
850895 template
851 auto partition(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
852 return std::partition(std::begin(Range), std::end(Range), P);
896 auto partition(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
897 return std::partition(adl_begin(Range), adl_end(Range), P);
853898 }
854899
855900 /// Provide wrappers to std::lower_bound which take ranges instead of having to
856901 /// pass begin/end explicitly.
857902 template
858 auto lower_bound(R &&Range, ForwardIt I) -> decltype(std::begin(Range)) {
859 return std::lower_bound(std::begin(Range), std::end(Range), I);
903 auto lower_bound(R &&Range, ForwardIt I) -> decltype(adl_begin(Range)) {
904 return std::lower_bound(adl_begin(Range), adl_end(Range), I);
860905 }
861906
862907 /// \brief Given a range of type R, iterate the entire range and return a
865910 template
866911 SmallVector>::type, Size>
867912 to_vector(R &&Range) {
868 return {std::begin(Range), std::end(Range)};
913 return {adl_begin(Range), adl_end(Range)};
869914 }
870915
871916 /// Provide a container algorithm similar to C++ Library Fundamentals v2's
251251 EXPECT_EQ(3, count(v, 1));
252252 EXPECT_EQ(2, count(v, 2));
253253 EXPECT_EQ(1, count(v, 3));
254 EXPECT_EQ(1, count(v, 4));
255 }
256
257 TEST(STLExtrasTest, for_each) {
258 std::vector v{ 0, 1, 2, 3, 4 };
259 int count = 0;
260
261 llvm::for_each(v, [&count](int) { ++count; });
262 EXPECT_EQ(5, count);
263 }
264
265 TEST(STLExtrasTest, ToVector) {
266 std::vector v = {'a', 'b', 'c'};
267 auto Enumerated = to_vector<4>(enumerate(v));
254 EXPECT_EQ(1, count(v, 4));
255 }
256
257 TEST(STLExtrasTest, for_each) {
258 std::vector v{0, 1, 2, 3, 4};
259 int count = 0;
260
261 llvm::for_each(v, [&count](int) { ++count; });
262 EXPECT_EQ(5, count);
263 }
264
265 TEST(STLExtrasTest, ToVector) {
266 std::vector v = {'a', 'b', 'c'};
267 auto Enumerated = to_vector<4>(enumerate(v));
268268 ASSERT_EQ(3u, Enumerated.size());
269269 for (size_t I = 0; I < v.size(); ++I) {
270270 EXPECT_EQ(I, Enumerated[I].index());
325325 EXPECT_EQ(7, V[3]);
326326 }
327327
328 }
328 namespace some_namespace {
329 struct some_struct {
330 std::vector data;
331 std::string swap_val;
332 };
333
334 std::vector::const_iterator begin(const some_struct &s) {
335 return s.data.begin();
336 }
337
338 std::vector::const_iterator end(const some_struct &s) {
339 return s.data.end();
340 }
341
342 void swap(some_struct &lhs, some_struct &rhs) {
343 // make swap visible as non-adl swap would even seem to
344 // work with std::swap which defaults to moving
345 lhs.swap_val = "lhs";
346 rhs.swap_val = "rhs";
347 }
348 } // namespace some_namespace
349
350 TEST(STLExtrasTest, ADLTest) {
351 some_namespace::some_struct s{{1, 2, 3, 4, 5}, ""};
352 some_namespace::some_struct s2{{2, 4, 6, 8, 10}, ""};
353
354 EXPECT_EQ(*adl_begin(s), 1);
355 EXPECT_EQ(*(adl_end(s) - 1), 5);
356
357 adl_swap(s, s2);
358 EXPECT_EQ(s.swap_val, "lhs");
359 EXPECT_EQ(s2.swap_val, "rhs");
360
361 int count = 0;
362 llvm::for_each(s, [&count](int) { ++count; });
363 EXPECT_EQ(5, count);
364 }
365
366 } // namespace