Add limited support for rvalue ranges in absl::c_copy*() and absl::c_move() algorithms

PiperOrigin-RevId: 931236330
Change-Id: I5dcf1356b36c604c31bb7e1deff307925c86ad06
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index 6928623..fef2911 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -192,16 +192,6 @@
                              std::remove_reference_t<C>>::value,
                      std::decay_t<OutputIterator>>;
 
-template <typename C, typename OutputRange>
-using ResultOfRangeToRangeTransfer =
-    std::enable_if_t<container_algorithm_internal::HasBeginEnd<
-                         std::add_lvalue_reference_t<OutputRange>>::value &&
-                         !container_algorithm_internal::IsMultidimensionalArray<
-                             std::remove_reference_t<OutputRange>>::value &&
-                         !container_algorithm_internal::IsMultidimensionalArray<
-                             std::remove_reference_t<C>>::value,
-                     void>;
-
 // Similar to std::is_pointer, but for testing if a type is a span.
 //
 // Note that subclasses of spans do not automatically qualify as spans, as they
@@ -231,6 +221,18 @@
     std::conditional_t<std::is_lvalue_reference<C>::value, std::true_type,
                        IsSpan<C>>;
 
+template <typename C, typename OutputRange>
+using ResultOfRangeToRangeTransfer =
+    std::enable_if_t<container_algorithm_internal::HasBeginEnd<
+                         std::add_lvalue_reference_t<OutputRange>>::value &&
+                         !container_algorithm_internal::IsMultidimensionalArray<
+                             std::remove_reference_t<OutputRange>>::value &&
+                         !container_algorithm_internal::IsMultidimensionalArray<
+                             std::remove_reference_t<C>>::value &&
+                         container_algorithm_internal::
+                             IsPermissibleDestinationRange<OutputRange>::value,
+                     void>;
+
 }  // namespace container_algorithm_internal
 
 // PUBLIC API
@@ -632,8 +634,7 @@
     InputSequence, OutputRange>
 c_copy(const InputSequence& input, OutputRange&& output) {
   container_algorithm_internal::AssertCopySize(input, output);
-  absl::c_copy(input, container_algorithm_internal::c_begin(
-                          std::forward<OutputRange>(output)));
+  absl::c_copy(input, container_algorithm_internal::c_begin(output));
 }
 
 // c_copy_n()
@@ -664,9 +665,7 @@
     C, OutputRange>
 c_copy_n(const C& input, Size n, OutputRange&& output) {
   container_algorithm_internal::AssertCopyNSize(input, n, output);
-  absl::c_copy_n(
-      input, n,
-      container_algorithm_internal::c_begin(std::forward<OutputRange>(output)));
+  absl::c_copy_n(input, n, container_algorithm_internal::c_begin(output));
 }
 
 // c_copy_if()
@@ -715,8 +714,8 @@
     C, OutputRange>
 c_move(C&& src, OutputRange&& dest) {
   container_algorithm_internal::AssertCopySize(src, dest);
-  absl::c_move(std::forward<C>(src), container_algorithm_internal::c_begin(
-                                         std::forward<OutputRange>(dest)));
+  absl::c_move(std::forward<C>(src),
+               container_algorithm_internal::c_begin(dest));
 }
 
 // c_move_backward()
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
index 6249e20..0b67001 100644
--- a/absl/algorithm/container_test.cc
+++ b/absl/algorithm/container_test.cc
@@ -762,6 +762,13 @@
   EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
 }
 
+TEST(MutatingTest, CopyToSpanRvalue) {
+  const std::vector<int> input = {1, 2, 3};
+  std::vector<int> actual = {0, 0, 0, 4, 5};
+  absl::c_copy(input, absl::MakeSpan(actual));
+  EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
+}
+
 TEST(MutatingTest, CopyNToContainer) {
   const std::vector<int> input = {1, 2, 3, 4, 5};
   std::vector<int> actual = {0, 0, 0, 0, 0};
@@ -769,6 +776,13 @@
   EXPECT_THAT(actual, ElementsAre(1, 2, 0, 0, 0));
 }
 
+TEST(MutatingTest, CopyNToSpanRvalue) {
+  const std::vector<int> input = {1, 2, 3, 4, 5};
+  std::vector<int> actual = {0, 0, 0, 0, 0};
+  absl::c_copy_n(input, 2, absl::MakeSpan(actual));
+  EXPECT_THAT(actual, ElementsAre(1, 2, 0, 0, 0));
+}
+
 TEST(MutatingTest, CopyNToContainerWithZeroN) {
   const std::vector<int> input = {1, 2, 3, 4, 5};
   std::vector<int> actual = {0, 0, 0, 0, 0};
@@ -1008,6 +1022,28 @@
   EXPECT_EQ(actual[3], nullptr);
 }
 
+TEST(MutatingTest, MoveToSpanRvalue) {
+  std::vector<std::unique_ptr<int>> input;
+  input.push_back(std::make_unique<int>(1));
+  input.push_back(std::make_unique<int>(2));
+  input.push_back(std::make_unique<int>(3));
+
+  std::vector<std::unique_ptr<int>> actual(5);
+  absl::c_move(input, absl::MakeSpan(actual));
+
+  EXPECT_EQ(input[0], nullptr);
+  EXPECT_EQ(input[1], nullptr);
+  EXPECT_EQ(input[2], nullptr);
+
+  ASSERT_NE(actual[0], nullptr);
+  EXPECT_EQ(*actual[0], 1);
+  ASSERT_NE(actual[1], nullptr);
+  EXPECT_EQ(*actual[1], 2);
+  ASSERT_NE(actual[2], nullptr);
+  EXPECT_EQ(*actual[2], 3);
+  EXPECT_EQ(actual[3], nullptr);
+}
+
 TEST(MutatingTest, MoveToDifferentContainerType) {
   std::list<std::unique_ptr<int>> input;
   input.push_back(std::make_unique<int>(1));
@@ -2624,12 +2660,25 @@
   using Vec = std::vector<int>;
   // Because AmbiguousType is both an iterator and a container,
   // the compiler should fail to resolve the c_copy overload.
-  static_assert(!CanCopy<Vec, AmbiguousType>::value,
+  static_assert(!CanCopy<Vec, AmbiguousType&>::value,
                 "Ambiguous types should not compile!");
-  static_assert(!CanCopyN<Vec, AmbiguousType>::value,
+  static_assert(!CanCopyN<Vec, AmbiguousType&>::value,
                 "Ambiguous types should not compile!");
 }
 
+TEST(CanCopyTest, CopyToRValue) {
+  using Vec = std::vector<int>;
+  using Span = absl::Span<int>;
+  static_assert(CanCopy<Vec, Span>::value,
+                "Should be able to copy to rvalue Span");
+  static_assert(!CanCopy<Vec, Vec>::value,
+                "Should not be able to copy to rvalue vector");
+  static_assert(CanCopyN<Vec, Span>::value,
+                "Should be able to copy_n to rvalue Span");
+  static_assert(!CanCopyN<Vec, Vec>::value,
+                "Should not be able to copy_n to rvalue vector");
+}
+
 TEST(CanMoveTest, MoveToMultiDimArray) {
   static_assert(CanMove<std::vector<int>, int (&)[10]>::value);
   static_assert(!CanMove<std::vector<int>, int (&)[2][2]>::value);
@@ -2644,10 +2693,19 @@
   using Vec = std::vector<int>;
   // Because AmbiguousType is both an iterator and a container,
   // the compiler should fail to resolve the c_move overload.
-  static_assert(!CanMove<Vec, AmbiguousType>::value,
+  static_assert(!CanMove<Vec, AmbiguousType&>::value,
                 "Ambiguous types should not compile!");
 }
 
+TEST(CanMoveTest, MoveToRValue) {
+  using Vec = std::vector<std::unique_ptr<int>>;
+  using Span = absl::Span<std::unique_ptr<int>>;
+  static_assert(CanMove<Vec, Span>::value,
+                "Should be able to move to rvalue Span");
+  static_assert(!CanMove<Vec, Vec>::value,
+                "Should not be able to move to rvalue vector");
+}
+
 template <typename C, typename T, typename = void>
 struct CanFill : std::false_type {};