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