Don't assume that iterators can be compared.

std::string_view in MSVC has iterators that aren't just pointers and
that don't allow comparisons between different objects - not even if
those objects are views into the same string!

Change-Id: I0b61ca4a42bcbb9eda85df47c5f233dbf488e107
Reviewed-on: https://code-review.googlesource.com/c/re2/+/59330
Reviewed-by: Julien Goodwin <julieng@google.com>
Reviewed-by: Paul Wankadia <junyer@google.com>
diff --git a/re2/bitstate.cc b/re2/bitstate.cc
index 320d1ee..877e548 100644
--- a/re2/bitstate.cc
+++ b/re2/bitstate.cc
@@ -293,9 +293,9 @@
   context_ = context;
   if (context_.data() == NULL)
     context_ = text;
-  if (prog_->anchor_start() && context_.begin() != text.begin())
+  if (prog_->anchor_start() && BeginPtr(context_) != BeginPtr(text))
     return false;
-  if (prog_->anchor_end() && context_.end() != text.end())
+  if (prog_->anchor_end() && EndPtr(context_) != EndPtr(text))
     return false;
   anchored_ = anchored || prog_->anchor_start();
   longest_ = longest || prog_->anchor_end();
@@ -377,7 +377,7 @@
   bool longest = kind != kFirstMatch;
   if (!b.Search(text, context, anchored, longest, match, nmatch))
     return false;
-  if (kind == kFullMatch && match[0].end() != text.end())
+  if (kind == kFullMatch && EndPtr(match[0]) != EndPtr(text))
     return false;
   return true;
 }
diff --git a/re2/dfa.cc b/re2/dfa.cc
index 583303e..d47c7d5 100644
--- a/re2/dfa.cc
+++ b/re2/dfa.cc
@@ -1488,15 +1488,15 @@
 
   int lastbyte;
   if (run_forward) {
-    if (params->text.end() == params->context.end())
+    if (EndPtr(params->text) == EndPtr(params->context))
       lastbyte = kByteEndText;
     else
-      lastbyte = params->text.end()[0] & 0xFF;
+      lastbyte = EndPtr(params->text)[0] & 0xFF;
   } else {
-    if (params->text.begin() == params->context.begin())
+    if (BeginPtr(params->text) == BeginPtr(params->context))
       lastbyte = kByteEndText;
     else
-      lastbyte = params->text.begin()[-1] & 0xFF;
+      lastbyte = BeginPtr(params->text)[-1] & 0xFF;
   }
 
   State* ns = s->next_[ByteMap(lastbyte)].load(std::memory_order_acquire);
@@ -1627,7 +1627,7 @@
   const StringPiece& context = params->context;
 
   // Sanity check: make sure that text lies within context.
-  if (text.begin() < context.begin() || text.end() > context.end()) {
+  if (BeginPtr(text) < BeginPtr(context) || EndPtr(text) > EndPtr(context)) {
     LOG(DFATAL) << "context does not contain text";
     params->start = DeadState;
     return true;
@@ -1637,13 +1637,13 @@
   int start;
   uint32_t flags;
   if (params->run_forward) {
-    if (text.begin() == context.begin()) {
+    if (BeginPtr(text) == BeginPtr(context)) {
       start = kStartBeginText;
       flags = kEmptyBeginText|kEmptyBeginLine;
-    } else if (text.begin()[-1] == '\n') {
+    } else if (BeginPtr(text)[-1] == '\n') {
       start = kStartBeginLine;
       flags = kEmptyBeginLine;
-    } else if (Prog::IsWordChar(text.begin()[-1] & 0xFF)) {
+    } else if (Prog::IsWordChar(BeginPtr(text)[-1] & 0xFF)) {
       start = kStartAfterWordChar;
       flags = kFlagLastWord;
     } else {
@@ -1651,13 +1651,13 @@
       flags = 0;
     }
   } else {
-    if (text.end() == context.end()) {
+    if (EndPtr(text) == EndPtr(context)) {
       start = kStartBeginText;
       flags = kEmptyBeginText|kEmptyBeginLine;
-    } else if (text.end()[0] == '\n') {
+    } else if (EndPtr(text)[0] == '\n') {
       start = kStartBeginLine;
       flags = kEmptyBeginLine;
-    } else if (Prog::IsWordChar(text.end()[0] & 0xFF)) {
+    } else if (Prog::IsWordChar(EndPtr(text)[0] & 0xFF)) {
       start = kStartAfterWordChar;
       flags = kFlagLastWord;
     } else {
@@ -1837,9 +1837,9 @@
     using std::swap;
     swap(caret, dollar);
   }
-  if (caret && context.begin() != text.begin())
+  if (caret && BeginPtr(context) != BeginPtr(text))
     return false;
-  if (dollar && context.end() != text.end())
+  if (dollar && EndPtr(context) != EndPtr(text))
     return false;
 
   // Handle full match by running an anchored longest match
diff --git a/re2/nfa.cc b/re2/nfa.cc
index e858451..c7339f8 100644
--- a/re2/nfa.cc
+++ b/re2/nfa.cc
@@ -456,14 +456,14 @@
     context = text;
 
   // Sanity check: make sure that text lies within context.
-  if (text.begin() < context.begin() || text.end() > context.end()) {
+  if (BeginPtr(text) < BeginPtr(context) || EndPtr(text) > EndPtr(context)) {
     LOG(DFATAL) << "context does not contain text";
     return false;
   }
 
-  if (prog_->anchor_start() && context.begin() != text.begin())
+  if (prog_->anchor_start() && BeginPtr(context) != BeginPtr(text))
     return false;
-  if (prog_->anchor_end() && context.end() != text.end())
+  if (prog_->anchor_end() && EndPtr(context) != EndPtr(text))
     return false;
   anchored |= prog_->anchor_start();
   if (prog_->anchor_end()) {
@@ -646,7 +646,7 @@
   }
   if (!nfa.Search(text, context, anchor == kAnchored, kind != kFirstMatch, match, nmatch))
     return false;
-  if (kind == kFullMatch && match[0].end() != text.end())
+  if (kind == kFullMatch && EndPtr(match[0]) != EndPtr(text))
     return false;
   return true;
 }
diff --git a/re2/onepass.cc b/re2/onepass.cc
index 66a62d9..2639746 100644
--- a/re2/onepass.cc
+++ b/re2/onepass.cc
@@ -237,9 +237,9 @@
   StringPiece context = const_context;
   if (context.data() == NULL)
     context = text;
-  if (anchor_start() && context.begin() != text.begin())
+  if (anchor_start() && BeginPtr(context) != BeginPtr(text))
     return false;
-  if (anchor_end() && context.end() != text.end())
+  if (anchor_end() && EndPtr(context) != EndPtr(text))
     return false;
   if (anchor_end())
     kind = kFullMatch;
diff --git a/re2/prog.h b/re2/prog.h
index 8ca9880..e701e8c 100644
--- a/re2/prog.h
+++ b/re2/prog.h
@@ -450,6 +450,17 @@
   Prog& operator=(const Prog&) = delete;
 };
 
+// std::string_view in MSVC has iterators that aren't just pointers and
+// that don't allow comparisons between different objects - not even if
+// those objects are views into the same string! Thus, we provide these
+// conversion functions for convenience.
+static inline const char* BeginPtr(const StringPiece& s) {
+  return s.data();
+}
+static inline const char* EndPtr(const StringPiece& s) {
+  return s.data() + s.size();
+}
+
 }  // namespace re2
 
 #endif  // RE2_PROG_H_
diff --git a/re2/re2.cc b/re2/re2.cc
index 128c8bd..150c5ad 100644
--- a/re2/re2.cc
+++ b/re2/re2.cc
@@ -920,7 +920,7 @@
   }
 
   if (consumed != NULL)
-    *consumed = static_cast<size_t>(vec[0].end() - text.begin());
+    *consumed = static_cast<size_t>(EndPtr(vec[0]) - BeginPtr(text));
 
   if (n == 0 || args == NULL) {
     // We are not interested in results
diff --git a/re2/testing/backtrack.cc b/re2/testing/backtrack.cc
index 216d259..920a453 100644
--- a/re2/testing/backtrack.cc
+++ b/re2/testing/backtrack.cc
@@ -103,9 +103,9 @@
   context_ = context;
   if (context_.data() == NULL)
     context_ = text;
-  if (prog_->anchor_start() && text.begin() > context_.begin())
+  if (prog_->anchor_start() && BeginPtr(text) > BeginPtr(context_))
     return false;
-  if (prog_->anchor_end() && text.end() < context_.end())
+  if (prog_->anchor_end() && EndPtr(text) < EndPtr(context_))
     return false;
   anchored_ = anchored | prog_->anchor_start();
   longest_ = longest | prog_->anchor_end();
@@ -267,7 +267,7 @@
   bool longest = kind != kFirstMatch;
   if (!b.Search(text, context, anchored, longest, match, nmatch))
     return false;
-  if (kind == kFullMatch && match[0].end() != text.end())
+  if (kind == kFullMatch && EndPtr(match[0]) != EndPtr(text))
     return false;
   return true;
 }
diff --git a/re2/testing/exhaustive_tester.cc b/re2/testing/exhaustive_tester.cc
index bdac381..b0409c3 100644
--- a/re2/testing/exhaustive_tester.cc
+++ b/re2/testing/exhaustive_tester.cc
@@ -67,8 +67,8 @@
       printf("-");
     else
       printf("%td-%td",
-             m[i].begin() - input.begin(),
-             m[i].end() - input.begin());
+             BeginPtr(m[i]) - BeginPtr(input),
+             EndPtr(m[i]) - BeginPtr(input));
   }
 }
 
diff --git a/re2/testing/tester.cc b/re2/testing/tester.cc
index d2ec4fb..b0c22f2 100644
--- a/re2/testing/tester.cc
+++ b/re2/testing/tester.cc
@@ -117,8 +117,8 @@
   if (s.data() == NULL)
     return "(?,?)";
   return StringPrintf("(%td,%td)",
-                      s.begin() - text.begin(),
-                      s.end() - text.begin());
+                      BeginPtr(s) - BeginPtr(text),
+                      EndPtr(s) - BeginPtr(text));
 }
 
 // Returns whether text contains non-ASCII (>= 0x80) bytes.
@@ -403,7 +403,7 @@
     case kEngineRE2:
     case kEngineRE2a:
     case kEngineRE2b: {
-      if (!re2_ || text.end() != context.end()) {
+      if (!re2_ || EndPtr(text) != EndPtr(context)) {
         result->skipped = true;
         break;
       }
@@ -418,8 +418,8 @@
 
       result->matched = re2_->Match(
           context,
-          static_cast<size_t>(text.begin() - context.begin()),
-          static_cast<size_t>(text.end() - context.begin()),
+          static_cast<size_t>(BeginPtr(text) - BeginPtr(context)),
+          static_cast<size_t>(EndPtr(text) - BeginPtr(context)),
           re_anchor,
           result->submatch,
           nsubmatch);
@@ -428,8 +428,8 @@
     }
 
     case kEnginePCRE: {
-      if (!re_ || text.begin() != context.begin() ||
-          text.end() != context.end()) {
+      if (!re_ || BeginPtr(text) != BeginPtr(context) ||
+          EndPtr(text) != EndPtr(context)) {
         result->skipped = true;
         break;
       }
@@ -606,9 +606,9 @@
     << " text "
     << CEscape(text)
     << " ("
-    << text.begin() - context.begin()
+    << BeginPtr(text) - BeginPtr(context)
     << ","
-    << text.end() - context.begin()
+    << EndPtr(text) - BeginPtr(context)
     << ") of context "
     << CEscape(context)
     << " (" << FormatKind(kind_)