• 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 #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:
Regex()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 
Init(const std::string & spec,std::string * error)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 
~Regex()91 inline Regex::~Regex() {}
92 
Match(const std::string & str)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
Init(const std::string & spec,std::string * error)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 
~Regex()124 inline Regex::~Regex() {
125   if (init_) {
126     regfree(&re_);
127   }
128 }
129 
Match(const std::string & str)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