Remove distinction between input/output views in fxcrt::Zip().

C++'s notion of a forwarding (universal) reference allows these
templates to bind to either rvalues or lvalues.

Change-Id: Ia75314dc5f8e9bf2c3cd41970752fd2bb17e5f60
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/127790
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fxcrt/zip.h b/core/fxcrt/zip.h
index 8902f19..0610ff7 100644
--- a/core/fxcrt/zip.h
+++ b/core/fxcrt/zip.h
@@ -19,7 +19,7 @@
 // Vastly simplified implementation of ideas from C++23 zip_view<>. Allows
 // safe traversal of two or three ranges with a single bounds check per
 // iteration.
-
+//
 // Example two range usage:
 //   struct RGB { uint8_t r; uint8_t g; uint8_t b; };
 //   const uint8_t gray[256] = { ... };
@@ -31,17 +31,13 @@
 //   }
 // which fills the first 256 elements of rgbs with the corresponding gray
 // value in each component, say.
-
+//
 // Differences include:
 // - Only zips together two or three views instead of N.
 // - Size is determined by the first view, which must be smaller than the
 //   other view(s).
-// - With two views, the first view is presumed to be "input-like" and is const.
-//   The second view is presumed to be "output-like", can be non-const, and
-//   can be assigned-to if desired.
-// - With three views, the first two views are presumed to be "input-like" and
-//   are const. The third view is is presumed to be "output-like", can be
-//   non-const, and can be assigned-to if desired.
+// - Views are passed as forwarding-references, so non-const views may be
+//   assigned-to in the body of the loop.
 // - Only those methods required to support use in a range-based for-loop
 //   are provided.
 
@@ -125,12 +121,12 @@
 };
 
 template <typename T, typename U>
-auto Zip(const T& first, U&& second) {
+auto Zip(T&& first, U&& second) {
   return ZipView2(pdfium::span(first), pdfium::span(second));
 }
 
 template <typename T, typename U, typename V>
-auto Zip(const T& first, const U& second, V&& third) {
+auto Zip(T&& first, U&& second, V&& third) {
   return ZipView3(pdfium::span(first), pdfium::span(second),
                   pdfium::span(third));
 }
diff --git a/core/fxcrt/zip_unittest.cpp b/core/fxcrt/zip_unittest.cpp
index 09a2891..211fd8d 100644
--- a/core/fxcrt/zip_unittest.cpp
+++ b/core/fxcrt/zip_unittest.cpp
@@ -37,16 +37,22 @@
 TEST(Zip, ActualZip) {
   const int stuff[] = {1, 2, 3};
   const int expected[] = {1, 2, 3, 0};
-  int output[4] = {};
-
-  for (auto [in, out] : Zip(stuff, output)) {
-    out = in;
+  {
+    int output[4] = {};
+    for (auto [in, out] : Zip(stuff, output)) {
+      out = in;
+    }
+    EXPECT_THAT(output, ElementsAreArray(expected));
   }
-  EXPECT_THAT(output, ElementsAreArray(expected));
-
-  // The "output" span can, in fact, be const so long as we don't assign to it.
-  for (auto [in, expect] : Zip(stuff, expected)) {
-    EXPECT_EQ(in, expect);
+  {
+    // Test that ordering of args doesn't matter, except for the size
+    // determination.
+    int output[4] = {};
+    auto sub_output = pdfium::make_span(output).first(3);
+    for (auto [out, in] : Zip(sub_output, stuff)) {
+      out = in;
+    }
+    EXPECT_THAT(output, ElementsAreArray(expected));
   }
 }
 
@@ -54,16 +60,30 @@
   const int stuff1[] = {1, 2, 3};
   const int stuff2[] = {4, 5, 6};
   const int expected[] = {5, 7, 9, 0};
-  int output[4] = {};
-
-  for (auto [in1, in2, out] : Zip(stuff1, stuff2, output)) {
-    out = in1 + in2;
+  {
+    int output[4] = {};
+    for (auto [in1, in2, out] : Zip(stuff1, stuff2, output)) {
+      out = in1 + in2;
+    }
+    EXPECT_THAT(output, ElementsAreArray(expected));
   }
-  EXPECT_THAT(output, ElementsAreArray(expected));
-
-  // The "output" span can, in fact, be const so long as we don't assign to it.
-  for (auto [in1, in2, expect] : Zip(stuff1, stuff2, output)) {
-    EXPECT_EQ(in1 + in2, expect);
+  {
+    // Test that ordering of args doesn't matter.
+    int output[4] = {};
+    for (auto [in1, out, in2] : Zip(stuff1, output, stuff2)) {
+      out = in1 + in2;
+    }
+    EXPECT_THAT(output, ElementsAreArray(expected));
+  }
+  {
+    // Test that ordering of args doesn't matter, except for the size
+    // determination.
+    int output[4] = {};
+    auto sub_output = pdfium::make_span(output).first(3);
+    for (auto [out, in1, in2] : Zip(sub_output, stuff1, stuff2)) {
+      out = in1 + in2;
+    }
+    EXPECT_THAT(output, ElementsAreArray(expected));
   }
 }