Optimise the layout of the `RE2` class.

In particular, `error_arg_` should be a pointer... that will almost
always be `empty_string`. Also, separate the relatively cold fields
from the relatively hot fields to be slightly friendlier to caches.

Bump SONAME accordingly.

Credit and gratitude to Clement Courbet for his suggestions.

Change-Id: I6553878bbae5e2aae650ad37a7755a833708af4b
Reviewed-on: https://code-review.googlesource.com/c/re2/+/60190
Reviewed-by: Perry Lorier <perryl@google.com>
Reviewed-by: Paul Wankadia <junyer@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e6828d8..f94b423 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,7 +19,7 @@
 
 # ABI version
 # http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
-set(SONAME 9)
+set(SONAME 10)
 
 set(EXTRA_TARGET_LINK_LIBRARIES)
 
diff --git a/Makefile b/Makefile
index 197c2b3..c24fd57 100644
--- a/Makefile
+++ b/Makefile
@@ -44,7 +44,7 @@
 
 # ABI version
 # http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
-SONAME=9
+SONAME=10
 
 # To rebuild the Tables generated by Perl and Python scripts (requires Internet
 # access for Unicode data), uncomment the following line:
diff --git a/re2/re2.cc b/re2/re2.cc
index c027133..e127e21 100644
--- a/re2/re2.cc
+++ b/re2/re2.cc
@@ -43,11 +43,11 @@
 const int RE2::Options::kDefaultMaxMem;  // initialized in re2.h
 
 RE2::Options::Options(RE2::CannedOptions opt)
-  : encoding_(opt == RE2::Latin1 ? EncodingLatin1 : EncodingUTF8),
+  : max_mem_(kDefaultMaxMem),
+    encoding_(opt == RE2::Latin1 ? EncodingLatin1 : EncodingUTF8),
     posix_syntax_(opt == RE2::POSIX),
     longest_match_(opt == RE2::POSIX),
     log_errors_(opt != RE2::Quiet),
-    max_mem_(kDefaultMaxMem),
     literal_(false),
     never_nl_(false),
     dot_nl_(false),
@@ -178,18 +178,20 @@
     empty_group_names = new std::map<int, std::string>;
   });
 
-  pattern_.assign(pattern.data(), pattern.size());
+  pattern_ = new std::string(pattern);
   options_.Copy(options);
   entire_regexp_ = NULL;
-  error_ = empty_string;
-  error_code_ = NoError;
-  error_arg_.clear();
-  prefix_.clear();
-  prefix_foldcase_ = false;
   suffix_regexp_ = NULL;
-  prog_ = NULL;
+  error_ = empty_string;
+  error_arg_ = empty_string;
+
   num_captures_ = -1;
+  error_code_ = NoError;
+  longest_match_ = options_.longest_match();
   is_one_pass_ = false;
+  prefix_foldcase_ = false;
+  prefix_.clear();
+  prog_ = NULL;
 
   rprog_ = NULL;
   named_groups_ = NULL;
@@ -197,25 +199,29 @@
 
   RegexpStatus status;
   entire_regexp_ = Regexp::Parse(
-    pattern_,
+    *pattern_,
     static_cast<Regexp::ParseFlags>(options_.ParseFlags()),
     &status);
   if (entire_regexp_ == NULL) {
     if (options_.log_errors()) {
-      LOG(ERROR) << "Error parsing '" << trunc(pattern_) << "': "
+      LOG(ERROR) << "Error parsing '" << trunc(*pattern_) << "': "
                  << status.Text();
     }
     error_ = new std::string(status.Text());
     error_code_ = RegexpErrorToRE2(status.code());
-    error_arg_ = std::string(status.error_arg());
+    error_arg_ = new std::string(status.error_arg());
     return;
   }
 
+  bool foldcase;
   re2::Regexp* suffix;
-  if (entire_regexp_->RequiredPrefix(&prefix_, &prefix_foldcase_, &suffix))
+  if (entire_regexp_->RequiredPrefix(&prefix_, &foldcase, &suffix)) {
+    prefix_foldcase_ = foldcase;
     suffix_regexp_ = suffix;
-  else
+  }
+  else {
     suffix_regexp_ = entire_regexp_->Incref();
+  }
 
   // Two thirds of the memory goes to the forward Prog,
   // one third to the reverse prog, because the forward
@@ -223,7 +229,7 @@
   prog_ = suffix_regexp_->CompileToProg(options_.max_mem()*2/3);
   if (prog_ == NULL) {
     if (options_.log_errors())
-      LOG(ERROR) << "Error compiling '" << trunc(pattern_) << "'";
+      LOG(ERROR) << "Error compiling '" << trunc(*pattern_) << "'";
     error_ = new std::string("pattern too large - compile failed");
     error_code_ = RE2::ErrorPatternTooLarge;
     return;
@@ -249,7 +255,8 @@
         re->suffix_regexp_->CompileToReverseProg(re->options_.max_mem() / 3);
     if (re->rprog_ == NULL) {
       if (re->options_.log_errors())
-        LOG(ERROR) << "Error reverse compiling '" << trunc(re->pattern_) << "'";
+        LOG(ERROR) << "Error reverse compiling '" << trunc(*re->pattern_)
+                   << "'";
       // We no longer touch error_ and error_code_ because failing to compile
       // the reverse Prog is not a showstopper: falling back to NFA execution
       // is fine. More importantly, an RE2 object is supposed to be logically
@@ -261,18 +268,21 @@
 }
 
 RE2::~RE2() {
+  if (group_names_ != empty_group_names)
+    delete group_names_;
+  if (named_groups_ != empty_named_groups)
+    delete named_groups_;
+  delete rprog_;
+  delete prog_;
+  if (error_arg_ != empty_string)
+    delete error_arg_;
+  if (error_ != empty_string)
+    delete error_;
   if (suffix_regexp_)
     suffix_regexp_->Decref();
   if (entire_regexp_)
     entire_regexp_->Decref();
-  delete prog_;
-  delete rprog_;
-  if (error_ != empty_string)
-    delete error_;
-  if (named_groups_ != NULL && named_groups_ != empty_named_groups)
-    delete named_groups_;
-  if (group_names_ != NULL &&  group_names_ != empty_group_names)
-    delete group_names_;
+  delete pattern_;
 }
 
 int RE2::ProgramSize() const {
@@ -686,9 +696,8 @@
   }
 
   Prog::Anchor anchor = Prog::kUnanchored;
-  Prog::MatchKind kind = Prog::kFirstMatch;
-  if (options_.longest_match())
-    kind = Prog::kLongestMatch;
+  Prog::MatchKind kind =
+      longest_match_ ? Prog::kLongestMatch : Prog::kFirstMatch;
 
   bool can_one_pass = is_one_pass_ && ncap <= Prog::kMaxOnePassCapture;
   bool can_bit_state = prog_->CanBitState();
@@ -720,7 +729,7 @@
           if (dfa_failed) {
             if (options_.log_errors())
               LOG(ERROR) << "DFA out of memory: "
-                         << "pattern length " << pattern_.size() << ", "
+                         << "pattern length " << pattern_->size() << ", "
                          << "program size " << prog->size() << ", "
                          << "list count " << prog->list_count() << ", "
                          << "bytemap range " << prog->bytemap_range();
@@ -740,7 +749,7 @@
         if (dfa_failed) {
           if (options_.log_errors())
             LOG(ERROR) << "DFA out of memory: "
-                       << "pattern length " << pattern_.size() << ", "
+                       << "pattern length " << pattern_->size() << ", "
                        << "program size " << prog_->size() << ", "
                        << "list count " << prog_->list_count() << ", "
                        << "bytemap range " << prog_->bytemap_range();
@@ -766,7 +775,7 @@
         if (dfa_failed) {
           if (options_.log_errors())
             LOG(ERROR) << "DFA out of memory: "
-                       << "pattern length " << pattern_.size() << ", "
+                       << "pattern length " << pattern_->size() << ", "
                        << "program size " << prog->size() << ", "
                        << "list count " << prog->list_count() << ", "
                        << "bytemap range " << prog->bytemap_range();
@@ -809,7 +818,7 @@
         if (dfa_failed) {
           if (options_.log_errors())
             LOG(ERROR) << "DFA out of memory: "
-                       << "pattern length " << pattern_.size() << ", "
+                       << "pattern length " << pattern_->size() << ", "
                        << "program size " << prog_->size() << ", "
                        << "list count " << prog_->list_count() << ", "
                        << "bytemap range " << prog_->bytemap_range();
diff --git a/re2/re2.h b/re2/re2.h
index df32ce3..38fdcb7 100644
--- a/re2/re2.h
+++ b/re2/re2.h
@@ -288,7 +288,7 @@
   // The string specification for this RE2.  E.g.
   //   RE2 re("ab*c?d+");
   //   re.pattern();    // "ab*c?d+"
-  const std::string& pattern() const { return pattern_; }
+  const std::string& pattern() const { return *pattern_; }
 
   // If RE2 could not be created properly, returns an error string.
   // Else returns the empty string.
@@ -300,7 +300,7 @@
 
   // If RE2 could not be created properly, returns the offending
   // portion of the regexp.
-  const std::string& error_arg() const { return error_arg_; }
+  const std::string& error_arg() const { return *error_arg_; }
 
   // Returns the program size, a very approximate measure of a regexp's "cost".
   // Larger numbers are more expensive than smaller numbers.
@@ -653,11 +653,11 @@
     };
 
     Options() :
+      max_mem_(kDefaultMaxMem),
       encoding_(EncodingUTF8),
       posix_syntax_(false),
       longest_match_(false),
       log_errors_(true),
-      max_mem_(kDefaultMaxMem),
       literal_(false),
       never_nl_(false),
       dot_nl_(false),
@@ -670,6 +670,9 @@
 
     /*implicit*/ Options(CannedOptions);
 
+    int64_t max_mem() const { return max_mem_; }
+    void set_max_mem(int64_t m) { max_mem_ = m; }
+
     Encoding encoding() const { return encoding_; }
     void set_encoding(Encoding encoding) { encoding_ = encoding; }
 
@@ -682,9 +685,6 @@
     bool log_errors() const { return log_errors_; }
     void set_log_errors(bool b) { log_errors_ = b; }
 
-    int64_t max_mem() const { return max_mem_; }
-    void set_max_mem(int64_t m) { max_mem_ = m; }
-
     bool literal() const { return literal_; }
     void set_literal(bool b) { literal_ = b; }
 
@@ -716,11 +716,11 @@
     int ParseFlags() const;
 
    private:
+    int64_t max_mem_;
     Encoding encoding_;
     bool posix_syntax_;
     bool longest_match_;
     bool log_errors_;
-    int64_t max_mem_;
     bool literal_;
     bool never_nl_;
     bool dot_nl_;
@@ -753,18 +753,23 @@
 
   re2::Prog* ReverseProg() const;
 
-  std::string pattern_;         // string regular expression
-  Options options_;             // option flags
-  re2::Regexp* entire_regexp_;  // parsed regular expression
-  const std::string* error_;    // error indicator (or points to empty string)
-  ErrorCode error_code_;        // error code
-  std::string error_arg_;       // fragment of regexp showing error
-  std::string prefix_;          // required prefix (before suffix_regexp_)
-  bool prefix_foldcase_;        // prefix_ is ASCII case-insensitive
-  re2::Regexp* suffix_regexp_;  // parsed regular expression, prefix_ removed
-  re2::Prog* prog_;             // compiled program for regexp
-  int num_captures_;            // number of capturing groups
-  bool is_one_pass_;            // can use prog_->SearchOnePass?
+  // First cache line is relatively cold fields.
+  const std::string* pattern_;    // string regular expression
+  Options options_;               // option flags
+  re2::Regexp* entire_regexp_;    // parsed regular expression
+  re2::Regexp* suffix_regexp_;    // parsed regular expression, prefix_ removed
+  const std::string* error_;      // error indicator (or points to empty string)
+  const std::string* error_arg_;  // fragment of regexp showing error (or ditto)
+
+  // Second cache line is relatively hot fields.
+  // These are ordered oddly to pack everything.
+  int num_captures_;              // number of capturing groups
+  ErrorCode error_code_ : 29;     // error code (29 bits is more than enough)
+  bool longest_match_ : 1;        // cached copy of options_.longest_match()
+  bool is_one_pass_ : 1;          // can use prog_->SearchOnePass?
+  bool prefix_foldcase_ : 1;      // prefix_ is ASCII case-insensitive
+  std::string prefix_;            // required prefix (before suffix_regexp_)
+  re2::Prog* prog_;               // compiled program for regexp
 
   // Reverse Prog for DFA execution only
   mutable re2::Prog* rprog_;