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