]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - utils/benchmark/src/re.h
Vendor import of llvm trunk r351319 (just before the release_80 branch
[FreeBSD/FreeBSD.git] / utils / benchmark / src / re.h
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 #if !defined(HAVE_STD_REGEX) && \
21     !defined(HAVE_GNU_POSIX_REGEX) && \
22     !defined(HAVE_POSIX_REGEX)
23   // No explicit regex selection; detect based on builtin hints.
24   #if defined(BENCHMARK_OS_LINUX) || defined(BENCHMARK_OS_APPLE)
25     #define HAVE_POSIX_REGEX 1
26   #elif __cplusplus >= 199711L
27     #define HAVE_STD_REGEX 1
28   #endif
29 #endif
30
31 // Prefer C regex libraries when compiling w/o exceptions so that we can
32 // correctly report errors.
33 #if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && \
34     defined(BENCHMARK_HAVE_STD_REGEX) && \
35     (defined(HAVE_GNU_POSIX_REGEX) || defined(HAVE_POSIX_REGEX))
36   #undef HAVE_STD_REGEX
37 #endif
38
39 #if defined(HAVE_STD_REGEX)
40   #include <regex>
41 #elif defined(HAVE_GNU_POSIX_REGEX)
42   #include <gnuregex.h>
43 #elif defined(HAVE_POSIX_REGEX)
44   #include <regex.h>
45 #else
46 #error No regular expression backend was found!
47 #endif
48 #include <string>
49
50 #include "check.h"
51
52 namespace benchmark {
53
54 // A wrapper around the POSIX regular expression API that provides automatic
55 // cleanup
56 class Regex {
57  public:
58   Regex() : init_(false) {}
59
60   ~Regex();
61
62   // Compile a regular expression matcher from spec.  Returns true on success.
63   //
64   // On failure (and if error is not nullptr), error is populated with a human
65   // readable error message if an error occurs.
66   bool Init(const std::string& spec, std::string* error);
67
68   // Returns whether str matches the compiled regular expression.
69   bool Match(const std::string& str);
70
71  private:
72   bool init_;
73 // Underlying regular expression object
74 #if defined(HAVE_STD_REGEX)
75   std::regex re_;
76 #elif defined(HAVE_POSIX_REGEX) || defined(HAVE_GNU_POSIX_REGEX)
77   regex_t re_;
78 #else
79   #error No regular expression backend implementation available
80 #endif
81 };
82
83 #if defined(HAVE_STD_REGEX)
84
85 inline bool Regex::Init(const std::string& spec, std::string* error) {
86 #ifdef BENCHMARK_HAS_NO_EXCEPTIONS
87   ((void)error); // suppress unused warning
88 #else
89   try {
90 #endif
91     re_ = std::regex(spec, std::regex_constants::extended);
92     init_ = true;
93 #ifndef BENCHMARK_HAS_NO_EXCEPTIONS
94   } catch (const std::regex_error& e) {
95     if (error) {
96       *error = e.what();
97     }
98   }
99 #endif
100   return init_;
101 }
102
103 inline Regex::~Regex() {}
104
105 inline bool Regex::Match(const std::string& str) {
106   if (!init_) {
107     return false;
108   }
109   return std::regex_search(str, re_);
110 }
111
112 #else
113 inline bool Regex::Init(const std::string& spec, std::string* error) {
114   int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB);
115   if (ec != 0) {
116     if (error) {
117       size_t needed = regerror(ec, &re_, nullptr, 0);
118       char* errbuf = new char[needed];
119       regerror(ec, &re_, errbuf, needed);
120
121       // regerror returns the number of bytes necessary to null terminate
122       // the string, so we move that when assigning to error.
123       CHECK_NE(needed, 0);
124       error->assign(errbuf, needed - 1);
125
126       delete[] errbuf;
127     }
128
129     return false;
130   }
131
132   init_ = true;
133   return true;
134 }
135
136 inline Regex::~Regex() {
137   if (init_) {
138     regfree(&re_);
139   }
140 }
141
142 inline bool Regex::Match(const std::string& str) {
143   if (!init_) {
144     return false;
145   }
146   return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0;
147 }
148 #endif
149
150 }  // end namespace benchmark
151
152 #endif  // BENCHMARK_RE_H_