[ADT] Zip range adapter

This augments the STLExtras toolset with a zip iterator and range
adapter. Zip comes in two varieties: `zip`, which will zip to the
shortest of the input ranges, and `zip_first`, which limits its
`begin() == end()` checks to just the first range.

Recommit r284035 after MSVC2013 support has been dropped.

Patch by: Bryant Wong <github.com/bryant>

Differential Revision: https://reviews.llvm.org/D23252

llvm-svn: 284623
diff --git a/llvm/unittests/ADT/IteratorTest.cpp b/llvm/unittests/ADT/IteratorTest.cpp
index 4f1d81d..a8d5b33 100644
--- a/llvm/unittests/ADT/IteratorTest.cpp
+++ b/llvm/unittests/ADT/IteratorTest.cpp
@@ -209,4 +209,67 @@
   EXPECT_EQ(A + 4, std::next(*Begin, 4));
 }
 
+TEST(ZipIteratorTest, Basic) {
+  using namespace std;
+  const SmallVector<unsigned, 6> pi{3, 1, 4, 1, 5, 9};
+  SmallVector<bool, 6> odd{1, 1, 0, 1, 1, 1};
+  const char message[] = "yynyyy\0";
+
+  for (auto tup : zip(pi, odd, message)) {
+    EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
+    EXPECT_EQ(get<0>(tup) & 0x01 ? 'y' : 'n', get<2>(tup));
+  }
+
+  // note the rvalue
+  for (auto tup : zip(pi, SmallVector<bool, 0>{1, 1, 0, 1, 1})) {
+    EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
+  }
+}
+
+TEST(ZipIteratorTest, ZipFirstBasic) {
+  using namespace std;
+  const SmallVector<unsigned, 6> pi{3, 1, 4, 1, 5, 9};
+  unsigned iters = 0;
+
+  for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
+    EXPECT_EQ(get<0>(tup), get<1>(tup) & 0x01);
+    iters += 1;
+  }
+
+  EXPECT_EQ(iters, 4u);
+}
+
+TEST(ZipIteratorTest, Mutability) {
+  using namespace std;
+  const SmallVector<unsigned, 4> pi{3, 1, 4, 1, 5, 9};
+  char message[] = "hello zip\0";
+
+  for (auto tup : zip(pi, message, message)) {
+    EXPECT_EQ(get<1>(tup), get<2>(tup));
+    get<2>(tup) = get<0>(tup) & 0x01 ? 'y' : 'n';
+  }
+
+  // note the rvalue
+  for (auto tup : zip(message, "yynyyyzip\0")) {
+    EXPECT_EQ(get<0>(tup), get<1>(tup));
+  }
+}
+
+TEST(ZipIteratorTest, ZipFirstMutability) {
+  using namespace std;
+  vector<unsigned> pi{3, 1, 4, 1, 5, 9};
+  unsigned iters = 0;
+
+  for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
+    get<1>(tup) = get<0>(tup);
+    iters += 1;
+  }
+
+  EXPECT_EQ(iters, 4u);
+
+  for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
+    EXPECT_EQ(get<0>(tup), get<1>(tup));
+  }
+}
+
 } // anonymous namespace