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 #if defined(HAVE_STD_REGEX)
     19 #include <regex>
     20 #elif defined(HAVE_GNU_POSIX_REGEX)
     21 #include <gnuregex.h>
     22 #elif defined(HAVE_POSIX_REGEX)
     23 #include <regex.h>
     24 #else
     25 #error No regular expression backend was found!
     26 #endif
     27 #include <string>
     28 
     29 #include "check.h"
     30 
     31 namespace benchmark {
     32 
     33 // A wrapper around the POSIX regular expression API that provides automatic
     34 // cleanup
     35 class Regex {
     36  public:
     37   Regex() : init_(false) {}
     38 
     39   ~Regex();
     40 
     41   // Compile a regular expression matcher from spec.  Returns true on success.
     42   //
     43   // On failure (and if error is not nullptr), error is populated with a human
     44   // readable error message if an error occurs.
     45   bool Init(const std::string& spec, std::string* error);
     46 
     47   // Returns whether str matches the compiled regular expression.
     48   bool Match(const std::string& str);
     49 
     50  private:
     51   bool init_;
     52 // Underlying regular expression object
     53 #if defined(HAVE_STD_REGEX)
     54   std::regex re_;
     55 #elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX)
     56   regex_t re_;
     57 #else
     58 #error No regular expression backend implementation available
     59 #endif
     60 };
     61 
     62 #if defined(HAVE_STD_REGEX)
     63 
     64 inline bool Regex::Init(const std::string& spec, std::string* error) {
     65   try {
     66     re_ = std::regex(spec, std::regex_constants::extended);
     67 
     68     init_ = true;
     69   } catch (const std::regex_error& e) {
     70     if (error) {
     71       *error = e.what();
     72     }
     73   }
     74   return init_;
     75 }
     76 
     77 inline Regex::~Regex() {}
     78 
     79 inline bool Regex::Match(const std::string& str) {
     80   if (!init_) {
     81     return false;
     82   }
     83   return std::regex_search(str, re_);
     84 }
     85 
     86 #else
     87 inline bool Regex::Init(const std::string& spec, std::string* error) {
     88   int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB);
     89   if (ec != 0) {
     90     if (error) {
     91       size_t needed = regerror(ec, &re_, nullptr, 0);
     92       char* errbuf = new char[needed];
     93       regerror(ec, &re_, errbuf, needed);
     94 
     95       // regerror returns the number of bytes necessary to null terminate
     96       // the string, so we move that when assigning to error.
     97       CHECK_NE(needed, 0);
     98       error->assign(errbuf, needed - 1);
     99 
    100       delete[] errbuf;
    101     }
    102 
    103     return false;
    104   }
    105 
    106   init_ = true;
    107   return true;
    108 }
    109 
    110 inline Regex::~Regex() {
    111   if (init_) {
    112     regfree(&re_);
    113   }
    114 }
    115 
    116 inline bool Regex::Match(const std::string& str) {
    117   if (!init_) {
    118     return false;
    119   }
    120   return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0;
    121 }
    122 #endif
    123 
    124 }  // end namespace benchmark
    125 
    126 #endif  // BENCHMARK_RE_H_
    127