Home | History | Annotate | Download | only in src
      1 // Copyright 2015 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #ifndef BENCHMARK_RE_H_
     16 #define BENCHMARK_RE_H_
     17 
     18 #include "internal_macros.h"
     19 
     20 // Prefer C regex libraries when compiling w/o exceptions so that we can
     21 // correctly report errors.
     22 #if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && defined(HAVE_STD_REGEX) && \
     23     (defined(HAVE_GNU_POSIX_REGEX) || defined(HAVE_POSIX_REGEX))
     24 #undef HAVE_STD_REGEX
     25 #endif
     26 
     27 #if defined(HAVE_STD_REGEX)
     28 #include <regex>
     29 #elif defined(HAVE_GNU_POSIX_REGEX)
     30 #include <gnuregex.h>
     31 #elif defined(HAVE_POSIX_REGEX)
     32 #include <regex.h>
     33 #else
     34 #error No regular expression backend was found!
     35 #endif
     36 #include <string>
     37 
     38 #include "check.h"
     39 
     40 namespace benchmark {
     41 
     42 // A wrapper around the POSIX regular expression API that provides automatic
     43 // cleanup
     44 class Regex {
     45  public:
     46   Regex() : init_(false) {}
     47 
     48   ~Regex();
     49 
     50   // Compile a regular expression matcher from spec.  Returns true on success.
     51   //
     52   // On failure (and if error is not nullptr), error is populated with a human
     53   // readable error message if an error occurs.
     54   bool Init(const std::string& spec, std::string* error);
     55 
     56   // Returns whether str matches the compiled regular expression.
     57   bool Match(const std::string& str);
     58 
     59  private:
     60   bool init_;
     61 // Underlying regular expression object
     62 #if defined(HAVE_STD_REGEX)
     63   std::regex re_;
     64 #elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX)
     65   regex_t re_;
     66 #else
     67 #error No regular expression backend implementation available
     68 #endif
     69 };
     70 
     71 #if defined(HAVE_STD_REGEX)
     72 
     73 inline bool Regex::Init(const std::string& spec, std::string* error) {
     74 #ifdef BENCHMARK_HAS_NO_EXCEPTIONS
     75   ((void)error); // suppress unused warning
     76 #else
     77   try {
     78 #endif
     79     re_ = std::regex(spec, std::regex_constants::extended);
     80     init_ = true;
     81 #ifndef BENCHMARK_HAS_NO_EXCEPTIONS
     82   } catch (const std::regex_error& e) {
     83     if (error) {
     84       *error = e.what();
     85     }
     86   }
     87 #endif
     88   return init_;
     89 }
     90 
     91 inline Regex::~Regex() {}
     92 
     93 inline bool Regex::Match(const std::string& str) {
     94   if (!init_) {
     95     return false;
     96   }
     97   return std::regex_search(str, re_);
     98 }
     99 
    100 #else
    101 inline bool Regex::Init(const std::string& spec, std::string* error) {
    102   int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB);
    103   if (ec != 0) {
    104     if (error) {
    105       size_t needed = regerror(ec, &re_, nullptr, 0);
    106       char* errbuf = new char[needed];
    107       regerror(ec, &re_, errbuf, needed);
    108 
    109       // regerror returns the number of bytes necessary to null terminate
    110       // the string, so we move that when assigning to error.
    111       CHECK_NE(needed, 0);
    112       error->assign(errbuf, needed - 1);
    113 
    114       delete[] errbuf;
    115     }
    116 
    117     return false;
    118   }
    119 
    120   init_ = true;
    121   return true;
    122 }
    123 
    124 inline Regex::~Regex() {
    125   if (init_) {
    126     regfree(&re_);
    127   }
    128 }
    129 
    130 inline bool Regex::Match(const std::string& str) {
    131   if (!init_) {
    132     return false;
    133   }
    134   return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0;
    135 }
    136 #endif
    137 
    138 }  // end namespace benchmark
    139 
    140 #endif  // BENCHMARK_RE_H_
    141