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