re2: add Set::Size

Among other uses, exposing RE2::Set::Size allows writing a function that
takes a Set and a string and reports whether the string matches every
regexp in the Set. Without Size, that function can't know how many
matches to expect.

Change-Id: Ia161a87f20d031be11a9df54b981631800af1528
Reviewed-on: https://code-review.googlesource.com/c/re2/+/63570
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/re2/set.cc b/re2/set.cc
index caebd24..3f2a1f0 100644
--- a/re2/set.cc
+++ b/re2/set.cc
@@ -55,6 +55,12 @@
   return *this;
 }
 
+int RE2::Set::Size() const {
+  if (!compiled_)
+    return static_cast<int>(elem_.size());
+  return size_;
+}
+
 int RE2::Set::Add(absl::string_view pattern, std::string* error) {
   if (compiled_) {
     ABSL_LOG(DFATAL) << "RE2::Set::Add() called after compiling";
diff --git a/re2/set.h b/re2/set.h
index 3fe419b..5a1e6d5 100644
--- a/re2/set.h
+++ b/re2/set.h
@@ -53,6 +53,10 @@
   // the error message from the parser.
   int Add(absl::string_view pattern, std::string* error);
 
+  // Returns the number of patterns in the set.
+  // Can be called before or after Compile().
+  int Size() const;
+
   // Compiles the set in preparation for matching.
   // Returns false if the compiler runs out of memory.
   // Add() must not be called again after Compile().
@@ -62,6 +66,7 @@
   // Returns true if text matches at least one of the regexps in the set.
   // Fills v (if not NULL) with the indices of the matching regexps.
   // Callers must not expect v to be sorted.
+  // The indices are in the half-open interval [0, Size()).
   bool Match(absl::string_view text, std::vector<int>* v) const;
 
   // As above, but populates error_info (if not NULL) when none of the regexps
diff --git a/re2/testing/set_test.cc b/re2/testing/set_test.cc
index b4aaf92..3282c16 100644
--- a/re2/testing/set_test.cc
+++ b/re2/testing/set_test.cc
@@ -17,10 +17,15 @@
 TEST(Set, Unanchored) {
   RE2::Set s(RE2::DefaultOptions, RE2::UNANCHORED);
 
+  ASSERT_EQ(s.Size(), 0);
   ASSERT_EQ(s.Add("foo", NULL), 0);
+  ASSERT_EQ(s.Size(), 1);
   ASSERT_EQ(s.Add("(", NULL), -1);
+  ASSERT_EQ(s.Size(), 1);
   ASSERT_EQ(s.Add("bar", NULL), 1);
+  ASSERT_EQ(s.Size(), 2);
   ASSERT_EQ(s.Compile(), true);
+  ASSERT_EQ(s.Size(), 2);
 
   ASSERT_EQ(s.Match("foobar", NULL), true);
   ASSERT_EQ(s.Match("fooba", NULL), true);