• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
Regex()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 
Init(const std::string & spec,std::string * error)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 
~Regex()77 inline Regex::~Regex() {}
78 
Match(const std::string & str)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
Init(const std::string & spec,std::string * error)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 
~Regex()110 inline Regex::~Regex() {
111   if (init_) {
112     regfree(&re_);
113   }
114 }
115 
Match(const std::string & str)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