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