Commits

Russ Cox committed 4816e3c

various updates and tweaks from Google

Comments (0)

Files changed (8)

re2/prefilter_tree.cc

 // Functions for triggering during search.
 void PrefilterTree::RegexpsGivenStrings(
     const vector<int>& matched_atoms,
-    vector<int>* regexps) {
+    vector<int>* regexps) const {
   regexps->clear();
   if (!compiled_) {
     LOG(WARNING) << "Compile() not called";
 }
 
 void PrefilterTree::PropagateMatch(const vector<int>& atom_ids,
-                                   IntMap* regexps) {
+                                   IntMap* regexps) const {
   IntMap count(entries_.size());
   IntMap work(entries_.size());
   for (int i = 0; i < atom_ids.size(); i++)

re2/prefilter_tree.h

   // content. The caller can use any string match engine to perform
   // this function.
   void RegexpsGivenStrings(const vector<int>& matched_atoms,
-                           vector<int>* regexps);
+                           vector<int>* regexps) const;
 
   // Print debug prefilter. Also prints unique ids associated with
   // nodes of the prefilter of the regexp.
 
   // Given the matching atoms, find the regexps to be triggered.
   void PropagateMatch(const vector<int>& atom_ids,
-                      IntMap* regexps);
+                      IntMap* regexps) const;
 
   // Returns the prefilter node that has the same NodeString as this
   // node. For the canonical node, returns node.
 static const int kMaxArgs = 16;
 static const int kVecSize = 1+kMaxArgs;
 
-// Special name for missing C++ arguments.
-RE2::Arg RE2::no_more_args((void*)NULL);
+const VariadicFunction2<bool, const StringPiece&, const RE2&, RE2::Arg, RE2::FullMatchN> RE2::FullMatch;
+const VariadicFunction2<bool, const StringPiece&, const RE2&, RE2::Arg, RE2::PartialMatchN> RE2::PartialMatch;
+const VariadicFunction2<bool, StringPiece*, const RE2&, RE2::Arg, RE2::ConsumeN> RE2::Consume;
+const VariadicFunction2<bool, StringPiece*, const RE2&, RE2::Arg, RE2::FindAndConsumeN> RE2::FindAndConsume;
 
 const int RE2::Options::kDefaultMaxMem;  // initialized in re2.h
 
 
 /***** Convenience interfaces *****/
 
-bool RE2::FullMatch(const StringPiece& text, const RE2& re,
-                   const Arg& a0,
-                   const Arg& a1,
-                   const Arg& a2,
-                   const Arg& a3,
-                   const Arg& a4,
-                   const Arg& a5,
-                   const Arg& a6,
-                   const Arg& a7,
-                   const Arg& a8,
-                   const Arg& a9,
-                   const Arg& a10,
-                   const Arg& a11,
-                   const Arg& a12,
-                   const Arg& a13,
-                   const Arg& a14,
-                   const Arg& a15) {
-  const Arg* args[kMaxArgs];
-  int n = 0;
-  if (&a0 == &no_more_args)  goto done; args[n++] = &a0;
-  if (&a1 == &no_more_args)  goto done; args[n++] = &a1;
-  if (&a2 == &no_more_args)  goto done; args[n++] = &a2;
-  if (&a3 == &no_more_args)  goto done; args[n++] = &a3;
-  if (&a4 == &no_more_args)  goto done; args[n++] = &a4;
-  if (&a5 == &no_more_args)  goto done; args[n++] = &a5;
-  if (&a6 == &no_more_args)  goto done; args[n++] = &a6;
-  if (&a7 == &no_more_args)  goto done; args[n++] = &a7;
-  if (&a8 == &no_more_args)  goto done; args[n++] = &a8;
-  if (&a9 == &no_more_args)  goto done; args[n++] = &a9;
-  if (&a10 == &no_more_args) goto done; args[n++] = &a10;
-  if (&a11 == &no_more_args) goto done; args[n++] = &a11;
-  if (&a12 == &no_more_args) goto done; args[n++] = &a12;
-  if (&a13 == &no_more_args) goto done; args[n++] = &a13;
-  if (&a14 == &no_more_args) goto done; args[n++] = &a14;
-  if (&a15 == &no_more_args) goto done; args[n++] = &a15;
-done:
-
+bool RE2::FullMatchN(const StringPiece& text, const RE2& re,
+                     const Arg* const args[], int n) {
   return re.DoMatch(text, ANCHOR_BOTH, NULL, args, n);
 }
 
-bool RE2::PartialMatch(const StringPiece& text, const RE2& re,
-                      const Arg& a0,
-                      const Arg& a1,
-                      const Arg& a2,
-                      const Arg& a3,
-                      const Arg& a4,
-                      const Arg& a5,
-                      const Arg& a6,
-                      const Arg& a7,
-                      const Arg& a8,
-                      const Arg& a9,
-                      const Arg& a10,
-                      const Arg& a11,
-                      const Arg& a12,
-                      const Arg& a13,
-                      const Arg& a14,
-                      const Arg& a15) {
-  const Arg* args[kMaxArgs];
-  int n = 0;
-  if (&a0 == &no_more_args)  goto done; args[n++] = &a0;
-  if (&a1 == &no_more_args)  goto done; args[n++] = &a1;
-  if (&a2 == &no_more_args)  goto done; args[n++] = &a2;
-  if (&a3 == &no_more_args)  goto done; args[n++] = &a3;
-  if (&a4 == &no_more_args)  goto done; args[n++] = &a4;
-  if (&a5 == &no_more_args)  goto done; args[n++] = &a5;
-  if (&a6 == &no_more_args)  goto done; args[n++] = &a6;
-  if (&a7 == &no_more_args)  goto done; args[n++] = &a7;
-  if (&a8 == &no_more_args)  goto done; args[n++] = &a8;
-  if (&a9 == &no_more_args)  goto done; args[n++] = &a9;
-  if (&a10 == &no_more_args) goto done; args[n++] = &a10;
-  if (&a11 == &no_more_args) goto done; args[n++] = &a11;
-  if (&a12 == &no_more_args) goto done; args[n++] = &a12;
-  if (&a13 == &no_more_args) goto done; args[n++] = &a13;
-  if (&a14 == &no_more_args) goto done; args[n++] = &a14;
-  if (&a15 == &no_more_args) goto done; args[n++] = &a15;
-done:
-
+bool RE2::PartialMatchN(const StringPiece& text, const RE2& re,
+                        const Arg* const args[], int n) {
   return re.DoMatch(text, UNANCHORED, NULL, args, n);
 }
 
-bool RE2::Consume(StringPiece* input, const RE2& re,
-                 const Arg& a0,
-                 const Arg& a1,
-                 const Arg& a2,
-                 const Arg& a3,
-                 const Arg& a4,
-                 const Arg& a5,
-                 const Arg& a6,
-                 const Arg& a7,
-                 const Arg& a8,
-                 const Arg& a9,
-                 const Arg& a10,
-                 const Arg& a11,
-                 const Arg& a12,
-                 const Arg& a13,
-                 const Arg& a14,
-                 const Arg& a15) {
-  const Arg* args[kMaxArgs];
-  int n = 0;
-  if (&a0 == &no_more_args)  goto done; args[n++] = &a0;
-  if (&a1 == &no_more_args)  goto done; args[n++] = &a1;
-  if (&a2 == &no_more_args)  goto done; args[n++] = &a2;
-  if (&a3 == &no_more_args)  goto done; args[n++] = &a3;
-  if (&a4 == &no_more_args)  goto done; args[n++] = &a4;
-  if (&a5 == &no_more_args)  goto done; args[n++] = &a5;
-  if (&a6 == &no_more_args)  goto done; args[n++] = &a6;
-  if (&a7 == &no_more_args)  goto done; args[n++] = &a7;
-  if (&a8 == &no_more_args)  goto done; args[n++] = &a8;
-  if (&a9 == &no_more_args)  goto done; args[n++] = &a9;
-  if (&a10 == &no_more_args) goto done; args[n++] = &a10;
-  if (&a11 == &no_more_args) goto done; args[n++] = &a11;
-  if (&a12 == &no_more_args) goto done; args[n++] = &a12;
-  if (&a13 == &no_more_args) goto done; args[n++] = &a13;
-  if (&a14 == &no_more_args) goto done; args[n++] = &a14;
-  if (&a15 == &no_more_args) goto done; args[n++] = &a15;
-done:
-
+bool RE2::ConsumeN(StringPiece* input, const RE2& re,
+                   const Arg* const args[], int n) {
   int consumed;
   if (re.DoMatch(*input, ANCHOR_START, &consumed, args, n)) {
     input->remove_prefix(consumed);
   }
 }
 
-bool RE2::FindAndConsume(StringPiece* input, const RE2& re,
-                        const Arg& a0,
-                        const Arg& a1,
-                        const Arg& a2,
-                        const Arg& a3,
-                        const Arg& a4,
-                        const Arg& a5,
-                        const Arg& a6,
-                        const Arg& a7,
-                        const Arg& a8,
-                        const Arg& a9,
-                        const Arg& a10,
-                        const Arg& a11,
-                        const Arg& a12,
-                        const Arg& a13,
-                        const Arg& a14,
-                        const Arg& a15) {
-  const Arg* args[kMaxArgs];
-  int n = 0;
-  if (&a0 == &no_more_args)  goto done; args[n++] = &a0;
-  if (&a1 == &no_more_args)  goto done; args[n++] = &a1;
-  if (&a2 == &no_more_args)  goto done; args[n++] = &a2;
-  if (&a3 == &no_more_args)  goto done; args[n++] = &a3;
-  if (&a4 == &no_more_args)  goto done; args[n++] = &a4;
-  if (&a5 == &no_more_args)  goto done; args[n++] = &a5;
-  if (&a6 == &no_more_args)  goto done; args[n++] = &a6;
-  if (&a7 == &no_more_args)  goto done; args[n++] = &a7;
-  if (&a8 == &no_more_args)  goto done; args[n++] = &a8;
-  if (&a9 == &no_more_args)  goto done; args[n++] = &a9;
-  if (&a10 == &no_more_args) goto done; args[n++] = &a10;
-  if (&a11 == &no_more_args) goto done; args[n++] = &a11;
-  if (&a12 == &no_more_args) goto done; args[n++] = &a12;
-  if (&a13 == &no_more_args) goto done; args[n++] = &a13;
-  if (&a14 == &no_more_args) goto done; args[n++] = &a14;
-  if (&a15 == &no_more_args) goto done; args[n++] = &a15;
-done:
-
+bool RE2::FindAndConsumeN(StringPiece* input, const RE2& re,
+                          const Arg* const args[], int n) {
   int consumed;
   if (re.DoMatch(*input, UNANCHORED, &consumed, args, n)) {
     input->remove_prefix(consumed);
 
 // Internal matcher - like Match() but takes Args not StringPieces.
 bool RE2::DoMatch(const StringPiece& text,
-                     Anchor anchor,
-                     int* consumed,
-                     const Arg* const* args,
-                     int n) const {
+                  Anchor anchor,
+                  int* consumed,
+                  const Arg* const* args,
+                  int n) const {
   if (!ok()) {
     if (options_.log_errors())
       LOG(ERROR) << "Invalid RE2: " << *error_;
 // -----------------------------------------------------------------------
 // PRE-COMPILED REGULAR EXPRESSIONS
 //
-// RE makes it easy to use any string as a regular expression, without
+// RE2 makes it easy to use any string as a regular expression, without
 // requiring a separate compilation step.
 //
-// If speed is of the essence, you can create a pre-compiled "RE"
+// If speed is of the essence, you can create a pre-compiled "RE2"
 // object from the pattern and use it multiple times.  If you do so,
 // you can typically parse text faster than with sscanf.
 //
 //     RE2::FindAndConsume(&input, "(\\w+)", &word)
 //
 // -----------------------------------------------------------------------
+// USING VARIABLE NUMBER OF ARGUMENTS
+//
+// The above operations require you to know the number of arguments
+// when you write the code.  This is not always possible or easy (for
+// example, the regular expression may be calculated at run time).
+// You can use the "N" version of the operations when the number of
+// match arguments are determined at run time.
+//
+// Example:
+//   const RE2::Arg* args[10];
+//   int n;
+//   // ... populate args with pointers to RE2::Arg values ...
+//   // ... set n to the number of RE2::Arg objects ...
+//   bool match = RE2::FullMatchN(input, pattern, args, n);
+//
+// The last statement is equivalent to
+//
+//   bool match = RE2::FullMatch(input, pattern,
+//                               *args[0], *args[1], ..., *args[n - 1]);
+//
+// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
 // PARSING HEX/OCTAL/C-RADIX NUMBERS
 //
 // By default, if you pass a pointer to a numeric value, the
 #include <map>
 #include <string>
 #include "re2/stringpiece.h"
+#include "re2/variadic_function.h"
 
 namespace re2 {
 using std::string;
 class Regexp;
 
 // Interface for regular expression matching.  Also corresponds to a
-// pre-compiled regular expression.  An "RE" object is safe for
+// pre-compiled regular expression.  An "RE2" object is safe for
 // concurrent use by multiple threads.
 class RE2 {
  public:
   // We convert user-passed pointers into special Arg objects
   class Arg;
-
-  // Marks end of arg list.
-  // ONLY USE IN OPTIONAL ARG DEFAULTS.
-  // DO NOT PASS EXPLICITLY.
-  static Arg no_more_args;
-
   class Options;
 
   enum ErrorCode {
   RE2(const StringPiece& pattern, const Options& option);
   ~RE2();
 
-  // Returns whether RE was created properly.
+  // Returns whether RE2 was created properly.
   bool ok() const { return error_code() == NoError; }
 
-  // The string specification for this RE.  E.g.
-  //   RE re("ab*c?d+");
+  // The string specification for this RE2.  E.g.
+  //   RE2 re("ab*c?d+");
   //   re.pattern();    // "ab*c?d+"
   const string& pattern() const { return pattern_; }
 
-  // If RE could not be created properly, returns an error string.
+  // If RE2 could not be created properly, returns an error string.
   // Else returns the empty string.
   const string& error() const { return *error_; }
 
-  // If RE could not be created properly, returns an error code.
+  // If RE2 could not be created properly, returns an error code.
   // Else returns RE2::NoError (== 0).
   ErrorCode error_code() const { return error_code_; }
 
-  // If RE could not be created properly, returns the offending
+  // If RE2 could not be created properly, returns the offending
   // portion of the regexp.
   const string& error_arg() const { return error_arg_; }
 
   // supplied, copies matched sub-patterns into them.
   //
   // You can pass in a "const char*" or a "string" for "text".
-  // You can pass in a "const char*" or a "string" or a "RE" for "pattern".
+  // You can pass in a "const char*" or a "string" or a "RE2" for "pattern".
   //
   // The provided pointer arguments can be pointers to any scalar numeric
   // type, or one of:
   // valid number):
   //    int number;
   //    RE2::FullMatch("abc", "[a-z]+(\\d+)?", &number);
-  static bool FullMatch(const StringPiece& text, const RE2& re,   // 3..16 args
-                        const Arg& ptr1 = no_more_args,
-                        const Arg& ptr2 = no_more_args,
-                        const Arg& ptr3 = no_more_args,
-                        const Arg& ptr4 = no_more_args,
-                        const Arg& ptr5 = no_more_args,
-                        const Arg& ptr6 = no_more_args,
-                        const Arg& ptr7 = no_more_args,
-                        const Arg& ptr8 = no_more_args,
-                        const Arg& ptr9 = no_more_args,
-                        const Arg& ptr10 = no_more_args,
-                        const Arg& ptr11 = no_more_args,
-                        const Arg& ptr12 = no_more_args,
-                        const Arg& ptr13 = no_more_args,
-                        const Arg& ptr14 = no_more_args,
-                        const Arg& ptr15 = no_more_args,
-                        const Arg& ptr16 = no_more_args);
+  static bool FullMatchN(const StringPiece& text, const RE2& re,
+                         const Arg* const args[], int argc);
+  static const VariadicFunction2<
+    bool, const StringPiece&, const RE2&, Arg, RE2::FullMatchN> FullMatch;
 
   // Exactly like FullMatch(), except that "pattern" is allowed to match
   // a substring of "text".
-  static bool PartialMatch(const StringPiece& text, const RE2& re, // 3..16 args
-                           const Arg& ptr1 = no_more_args,
-                           const Arg& ptr2 = no_more_args,
-                           const Arg& ptr3 = no_more_args,
-                           const Arg& ptr4 = no_more_args,
-                           const Arg& ptr5 = no_more_args,
-                           const Arg& ptr6 = no_more_args,
-                           const Arg& ptr7 = no_more_args,
-                           const Arg& ptr8 = no_more_args,
-                           const Arg& ptr9 = no_more_args,
-                           const Arg& ptr10 = no_more_args,
-                           const Arg& ptr11 = no_more_args,
-                           const Arg& ptr12 = no_more_args,
-                           const Arg& ptr13 = no_more_args,
-                           const Arg& ptr14 = no_more_args,
-                           const Arg& ptr15 = no_more_args,
-                           const Arg& ptr16 = no_more_args);
+  static bool PartialMatchN(const StringPiece& text, const RE2& re, // 3..16 args
+                            const Arg* const args[], int argc);
+  static const VariadicFunction2<
+    bool, const StringPiece&, const RE2&, Arg, RE2::PartialMatchN> PartialMatch;
 
   // Like FullMatch() and PartialMatch(), except that pattern has to
   // match a prefix of "text", and "input" is advanced past the matched
   // text.  Note: "input" is modified iff this routine returns true.
-  static bool Consume(StringPiece* input, const RE2& pattern, // 3..16 args
-                      const Arg& ptr1 = no_more_args,
-                      const Arg& ptr2 = no_more_args,
-                      const Arg& ptr3 = no_more_args,
-                      const Arg& ptr4 = no_more_args,
-                      const Arg& ptr5 = no_more_args,
-                      const Arg& ptr6 = no_more_args,
-                      const Arg& ptr7 = no_more_args,
-                      const Arg& ptr8 = no_more_args,
-                      const Arg& ptr9 = no_more_args,
-                      const Arg& ptr10 = no_more_args,
-                      const Arg& ptr11 = no_more_args,
-                      const Arg& ptr12 = no_more_args,
-                      const Arg& ptr13 = no_more_args,
-                      const Arg& ptr14 = no_more_args,
-                      const Arg& ptr15 = no_more_args,
-                      const Arg& ptr16 = no_more_args);
+  static bool ConsumeN(StringPiece* input, const RE2& pattern, // 3..16 args
+                       const Arg* const args[], int argc);
+  static const VariadicFunction2<
+    bool, StringPiece*, const RE2&, Arg, RE2::ConsumeN> Consume;
 
   // Like Consume(..), but does not anchor the match at the beginning of the
   // string.  That is, "pattern" need not start its match at the beginning of
   // "input".  For example, "FindAndConsume(s, "(\\w+)", &word)" finds the next
   // word in "s" and stores it in "word".
-  static bool FindAndConsume(StringPiece* input, const RE2& pattern,
-                             const Arg& ptr1 = no_more_args,
-                             const Arg& ptr2 = no_more_args,
-                             const Arg& ptr3 = no_more_args,
-                             const Arg& ptr4 = no_more_args,
-                             const Arg& ptr5 = no_more_args,
-                             const Arg& ptr6 = no_more_args,
-                             const Arg& ptr7 = no_more_args,
-                             const Arg& ptr8 = no_more_args,
-                             const Arg& ptr9 = no_more_args,
-                             const Arg& ptr10 = no_more_args,
-                             const Arg& ptr11 = no_more_args,
-                             const Arg& ptr12 = no_more_args,
-                             const Arg& ptr13 = no_more_args,
-                             const Arg& ptr14 = no_more_args,
-                             const Arg& ptr15 = no_more_args,
-                             const Arg& ptr16 = no_more_args);
+  static bool FindAndConsumeN(StringPiece* input, const RE2& pattern,
+                             const Arg* const args[], int argc);
+  static const VariadicFunction2<
+    bool, StringPiece*, const RE2&, Arg, RE2::FindAndConsumeN> FindAndConsume;
 
   // Replace the first match of "pattern" in "str" with "rewrite".
   // Within "rewrite", backslash-escaped digits (\1 to \9) can be
   // Returns true if match found, false if not.
   // On a successful match, fills in match[] (up to nmatch entries)
   // with information about submatches.
-  // I.e. matching RE("(foo)|(bar)baz") on "barbazbla" will return true,
+  // I.e. matching RE2("(foo)|(bar)baz") on "barbazbla" will return true,
   // setting match[0] = "barbaz", match[1] = NULL, match[2] = "bar",
   // match[3] = NULL, ..., up to match[nmatch-1] = NULL.
   //

re2/testing/exhaustive1_test.cc

                  7, Explode("ab"), "(?:%s)", "");
 
   // This would be a great test, but it runs forever when PCRE is enabled.
-  if (strstr("PCRE", FLAGS_regexp_engines.c_str()))
+  if (strstr("PCRE", FLAGS_regexp_engines.c_str()) == NULL)
     ExhaustiveTest(4, 3, Split(" ", "a (a)"), ops,
                    100, Explode("a"), "(?:%s)", "");
 }

re2/testing/re2_test.cc

   CHECK(! RE2::Consume(&input, r, &word)) << " input: " << input;
 }
 
+TEST(RE2, ConsumeN) {
+  const string s(" one two three 4");
+  StringPiece input(s);
+
+  RE2::Arg argv[2];
+  const RE2::Arg* const args[2] = { &argv[0], &argv[1] };
+
+  // 0 arg
+  EXPECT_TRUE(RE2::ConsumeN(&input, "\\s*(\\w+)", args, 0));  // Skips "one".
+
+  // 1 arg
+  string word;
+  argv[0] = &word;
+  EXPECT_TRUE(RE2::ConsumeN(&input, "\\s*(\\w+)", args, 1));
+  EXPECT_EQ("two", word);
+
+  // Multi-args
+  int n;
+  argv[1] = &n;
+  EXPECT_TRUE(RE2::ConsumeN(&input, "\\s*(\\w+)\\s*(\\d+)", args, 2));
+  EXPECT_EQ("three", word);
+  EXPECT_EQ(4, n);
+}
+
 TEST(RE2, FindAndConsume) {
   VLOG(1) << "TestFindAndConsume";
 
   CHECK_EQ(input, "");
 }
 
+TEST(RE2, FindAndConsumeN) {
+  const string s(" one two three 4");
+  StringPiece input(s);
+
+  RE2::Arg argv[2];
+  const RE2::Arg* const args[2] = { &argv[0], &argv[1] };
+
+  // 0 arg
+  EXPECT_TRUE(RE2::FindAndConsumeN(&input, "(\\w+)", args, 0));  // Skips "one".
+
+  // 1 arg
+  string word;
+  argv[0] = &word;
+  EXPECT_TRUE(RE2::FindAndConsumeN(&input, "(\\w+)", args, 1));
+  EXPECT_EQ("two", word);
+
+  // Multi-args
+  int n;
+  argv[1] = &n;
+  EXPECT_TRUE(RE2::FindAndConsumeN(&input, "(\\w+)\\s*(\\d+)", args, 2));
+  EXPECT_EQ("three", word);
+  EXPECT_EQ(4, n);
+}
+
 TEST(RE2, MatchNumberPeculiarity) {
   VLOG(1) << "TestMatchNumberPeculiarity";
 
   CHECK(RE2::PartialMatch("x", "((((((((((((((((((((x))))))))))))))))))))"));
 }
 
+TEST(RE2, PartialMatchN) {
+  RE2::Arg argv[2];
+  const RE2::Arg* const args[2] = { &argv[0], &argv[1] };
+
+  // 0 arg
+  EXPECT_TRUE(RE2::PartialMatchN("hello", "e.*o", args, 0));
+  EXPECT_FALSE(RE2::PartialMatchN("othello", "a.*o", args, 0));
+
+  // 1 arg
+  int i;
+  argv[0] = &i;
+  EXPECT_TRUE(RE2::PartialMatchN("1001 nights", "(\\d+)", args, 1));
+  EXPECT_EQ(1001, i);
+  EXPECT_FALSE(RE2::PartialMatchN("three", "(\\d+)", args, 1));
+
+  // Multi-arg
+  string s;
+  argv[1] = &s;
+  EXPECT_TRUE(RE2::PartialMatchN("answer: 42:life", "(\\d+):(\\w+)", args, 2));
+  EXPECT_EQ(42, i);
+  EXPECT_EQ("life", s);
+  EXPECT_FALSE(RE2::PartialMatchN("hi1", "(\\w+)(1)", args, 2));
+}
+
 TEST(RE2, FullMatchZeroArg) {
   // Zero-arg
   CHECK(RE2::FullMatch("1001", "\\d+"));
   CHECK_EQ(i, 1234);
 }
 
+TEST(RE2, FullMatchN) {
+  RE2::Arg argv[2];
+  const RE2::Arg* const args[2] = { &argv[0], &argv[1] };
+
+  // 0 arg
+  EXPECT_TRUE(RE2::FullMatchN("hello", "h.*o", args, 0));
+  EXPECT_FALSE(RE2::FullMatchN("othello", "h.*o", args, 0));
+
+  // 1 arg
+  int i;
+  argv[0] = &i;
+  EXPECT_TRUE(RE2::FullMatchN("1001", "(\\d+)", args, 1));
+  EXPECT_EQ(1001, i);
+  EXPECT_FALSE(RE2::FullMatchN("three", "(\\d+)", args, 1));
+
+  // Multi-arg
+  string s;
+  argv[1] = &s;
+  EXPECT_TRUE(RE2::FullMatchN("42:life", "(\\d+):(\\w+)", args, 2));
+  EXPECT_EQ(42, i);
+  EXPECT_EQ("life", s);
+  EXPECT_FALSE(RE2::FullMatchN("hi1", "(\\w+)(1)", args, 2));
+}
+
 TEST(RE2, FullMatchIgnoredArg) {
   int i;
   string s;

re2/variadic_function.h

+// Copyright 2010 The RE2 Authors.  All Rights Reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef RE2_VARIADIC_FUNCTION_H_
+#define RE2_VARIADIC_FUNCTION_H_
+
+namespace re2 {
+
+template <typename Result, typename Param0, typename Param1, typename Arg,
+          Result (*Func)(Param0, Param1, const Arg* const [], int count)>
+class VariadicFunction2 {
+ public:
+  VariadicFunction2() {}
+
+  Result operator()(Param0 p0, Param1 p1) const {
+    return Func(p0, p1, 0, 0);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0) const {
+    const Arg* const args[] = { &a0 };
+    return Func(p0, p1, args, 1);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1) const {
+    const Arg* const args[] = { &a0, &a1 };
+    return Func(p0, p1, args, 2);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2) const {
+    const Arg* const args[] = { &a0, &a1, &a2 };
+    return Func(p0, p1, args, 3);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3 };
+    return Func(p0, p1, args, 4);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4 };
+    return Func(p0, p1, args, 5);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5 };
+    return Func(p0, p1, args, 6);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6 };
+    return Func(p0, p1, args, 7);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7 };
+    return Func(p0, p1, args, 8);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 };
+    return Func(p0, p1, args, 9);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9 };
+    return Func(p0, p1, args, 10);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10 };
+    return Func(p0, p1, args, 11);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11 };
+    return Func(p0, p1, args, 12);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12 };
+    return Func(p0, p1, args, 13);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13 };
+    return Func(p0, p1, args, 14);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14 };
+    return Func(p0, p1, args, 15);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15 };
+    return Func(p0, p1, args, 16);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16 };
+    return Func(p0, p1, args, 17);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17 };
+    return Func(p0, p1, args, 18);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18 };
+    return Func(p0, p1, args, 19);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19 };
+    return Func(p0, p1, args, 20);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19,
+        &a20 };
+    return Func(p0, p1, args, 21);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21 };
+    return Func(p0, p1, args, 22);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22 };
+    return Func(p0, p1, args, 23);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22, const Arg& a23) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23 };
+    return Func(p0, p1, args, 24);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22, const Arg& a23, const Arg& a24) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24 };
+    return Func(p0, p1, args, 25);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22, const Arg& a23, const Arg& a24, const Arg& a25) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25 };
+    return Func(p0, p1, args, 26);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22, const Arg& a23, const Arg& a24, const Arg& a25,
+      const Arg& a26) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26 };
+    return Func(p0, p1, args, 27);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22, const Arg& a23, const Arg& a24, const Arg& a25,
+      const Arg& a26, const Arg& a27) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27 };
+    return Func(p0, p1, args, 28);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22, const Arg& a23, const Arg& a24, const Arg& a25,
+      const Arg& a26, const Arg& a27, const Arg& a28) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28 };
+    return Func(p0, p1, args, 29);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22, const Arg& a23, const Arg& a24, const Arg& a25,
+      const Arg& a26, const Arg& a27, const Arg& a28, const Arg& a29) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29 };
+    return Func(p0, p1, args, 30);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22, const Arg& a23, const Arg& a24, const Arg& a25,
+      const Arg& a26, const Arg& a27, const Arg& a28, const Arg& a29,
+      const Arg& a30) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30 };
+    return Func(p0, p1, args, 31);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg& a0, const Arg& a1,
+      const Arg& a2, const Arg& a3, const Arg& a4, const Arg& a5,
+      const Arg& a6, const Arg& a7, const Arg& a8, const Arg& a9,
+      const Arg& a10, const Arg& a11, const Arg& a12, const Arg& a13,
+      const Arg& a14, const Arg& a15, const Arg& a16, const Arg& a17,
+      const Arg& a18, const Arg& a19, const Arg& a20, const Arg& a21,
+      const Arg& a22, const Arg& a23, const Arg& a24, const Arg& a25,
+      const Arg& a26, const Arg& a27, const Arg& a28, const Arg& a29,
+      const Arg& a30, const Arg& a31) const {
+    const Arg* const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30, &a31 };
+    return Func(p0, p1, args, 32);
+  }
+};
+
+}  // namespace re2
+
+#endif  // RE2_VARIADIC_FUNCTION_H_
 class Thread {
  public:
   Thread();
-  ~Thread();
+  virtual ~Thread();
   void Start();
   void Join();
   void SetJoinable(bool);