`UnorderedElementsAre()`: Allow matching containers where `end` is a [sentinel](https://en.cppreference.com/cpp/iterator/sentinel_for). `ElementsAre` already supports that.

PiperOrigin-RevId: 971869110
Change-Id: I1316463fbd0b532bdf5d636d47165aace84b3801
diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h
index 9caee1d..800b767 100644
--- a/googlemock/include/gmock/gmock-matchers.h
+++ b/googlemock/include/gmock/gmock-matchers.h
@@ -3971,8 +3971,8 @@
   }
 
  private:
-  template <typename ElementIter>
-  MatchMatrix AnalyzeElements(ElementIter elem_first, ElementIter elem_last,
+  template <typename ElementIter, typename ElementIterEnd>
+  MatchMatrix AnalyzeElements(ElementIter elem_first, ElementIterEnd elem_last,
                               ::std::vector<std::string>* element_printouts,
                               MatchResultListener* listener) const {
     element_printouts->clear();
diff --git a/googlemock/test/gmock-matchers-containers_test.cc b/googlemock/test/gmock-matchers-containers_test.cc
index 697509f..e7969a0 100644
--- a/googlemock/test/gmock-matchers-containers_test.cc
+++ b/googlemock/test/gmock-matchers-containers_test.cc
@@ -78,6 +78,52 @@
 
 INSTANTIATE_GTEST_MATCHER_TEST_P(ElementsAreTest);
 
+// A range of decreasing, positive integers.
+class DecreasingIntRange {
+ public:
+  explicit DecreasingIntRange(int start) : v_(start) {}
+
+  struct Sentinel {};
+
+  class Iterator {
+   public:
+    using difference_type = std::ptrdiff_t;
+    using value_type = int;
+    using iterator_category = std::input_iterator_tag;
+    using pointer = void;
+    using reference = int;
+
+    explicit Iterator(int v) : v_(v) {}
+
+    int operator*() const { return v_; }
+
+    Iterator& operator++() {
+      --v_;
+      return *this;
+    }
+    Iterator operator++(int) {
+      auto tmp = *this;
+      ++*this;
+      return tmp;
+    }
+
+    bool operator==(const Iterator& other) const { return v_ == other.v_; }
+    bool operator!=(const Iterator& other) const { return v_ != other.v_; }
+
+    bool operator==(const Sentinel&) const { return v_ < 0; }
+    bool operator!=(const Sentinel&) const { return v_ >= 0; }
+
+   private:
+    int v_;
+  };
+
+  Iterator begin() const { return Iterator(v_); }
+  Sentinel end() const { return Sentinel{}; }
+
+ private:
+  int v_;
+};
+
 // Tests the variadic version of the ElementsAreMatcher
 TEST(ElementsAreTest, HugeMatcher) {
   vector<int> test_vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
@@ -87,6 +133,13 @@
                           Eq(8), Eq(9), Eq(10), Gt(1), Eq(12)));
 }
 
+// Tests ElementsAreMatcher with a range that uses a sentinel.
+TEST(ElementsAreTest, HugeMatcherSentinel) {
+  DecreasingIntRange range(3);
+
+  EXPECT_THAT(range, ElementsAre(Eq(3), Eq(2), Eq(1), Eq(0)));
+}
+
 // Tests the variadic version of the UnorderedElementsAreMatcher
 TEST(ElementsAreTest, HugeMatcherStr) {
   vector<std::string> test_vector{
@@ -105,6 +158,13 @@
                                Eq(3), Eq(9), Eq(12), Eq(11), Ne(122)));
 }
 
+// Tests the UnorderedElementsAreMatcher with a range that uses a sentinel.
+TEST(ElementsAreTest, HugeMatcherUnorderedSentinel) {
+  DecreasingIntRange range(3);
+
+  EXPECT_THAT(range, UnorderedElementsAre(Eq(2), Eq(1), Eq(3), Eq(0)));
+}
+
 // Tests that ASSERT_THAT() and EXPECT_THAT() work when the value
 // matches the matcher.
 TEST(MatcherAssertionTest, WorksWhenMatcherIsSatisfied) {