Coverage Report

Created: 2025-09-05 08:05

/src/duckdb/third_party/re2/re2/walker-inl.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2006 The RE2 Authors.  All Rights Reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
5
#ifndef RE2_WALKER_INL_H_
6
#define RE2_WALKER_INL_H_
7
8
// Helper class for traversing Regexps without recursion.
9
// Clients should declare their own subclasses that override
10
// the PreVisit and PostVisit methods, which are called before
11
// and after visiting the subexpressions.
12
13
// Not quite the Visitor pattern, because (among other things)
14
// the Visitor pattern is recursive.
15
16
#include <stack>
17
18
#include "util/logging.h"
19
#include "re2/regexp.h"
20
21
namespace duckdb_re2 {
22
23
template<typename T> struct WalkState;
24
25
template<typename T> class Regexp::Walker {
26
 public:
27
  Walker();
28
  virtual ~Walker();
29
30
  // Virtual method called before visiting re's children.
31
  // PreVisit passes ownership of its return value to its caller.
32
  // The Arg* that PreVisit returns will be passed to PostVisit as pre_arg
33
  // and passed to the child PreVisits and PostVisits as parent_arg.
34
  // At the top-most Regexp, parent_arg is arg passed to walk.
35
  // If PreVisit sets *stop to true, the walk does not recurse
36
  // into the children.  Instead it behaves as though the return
37
  // value from PreVisit is the return value from PostVisit.
38
  // The default PreVisit returns parent_arg.
39
  virtual T PreVisit(Regexp* re, T parent_arg, bool* stop);
40
41
  // Virtual method called after visiting re's children.
42
  // The pre_arg is the T that PreVisit returned.
43
  // The child_args is a vector of the T that the child PostVisits returned.
44
  // PostVisit takes ownership of pre_arg.
45
  // PostVisit takes ownership of the Ts
46
  // in *child_args, but not the vector itself.
47
  // PostVisit passes ownership of its return value
48
  // to its caller.
49
  // The default PostVisit simply returns pre_arg.
50
  virtual T PostVisit(Regexp* re, T parent_arg, T pre_arg,
51
                      T* child_args, int nchild_args);
52
53
  // Virtual method called to copy a T,
54
  // when Walk notices that more than one child is the same re.
55
  virtual T Copy(T arg);
56
57
  // Virtual method called to do a "quick visit" of the re,
58
  // but not its children.  Only called once the visit budget
59
  // has been used up and we're trying to abort the walk
60
  // as quickly as possible.  Should return a value that
61
  // makes sense for the parent PostVisits still to be run.
62
  // This function is (hopefully) only called by
63
  // WalkExponential, but must be implemented by all clients,
64
  // just in case.
65
  virtual T ShortVisit(Regexp* re, T parent_arg) = 0;
66
67
  // Walks over a regular expression.
68
  // Top_arg is passed as parent_arg to PreVisit and PostVisit of re.
69
  // Returns the T returned by PostVisit on re.
70
  T Walk(Regexp* re, T top_arg);
71
72
  // Like Walk, but doesn't use Copy.  This can lead to
73
  // exponential runtimes on cross-linked Regexps like the
74
  // ones generated by Simplify.  To help limit this,
75
  // at most max_visits nodes will be visited and then
76
  // the walk will be cut off early.
77
  // If the walk *is* cut off early, ShortVisit(re)
78
  // will be called on regexps that cannot be fully
79
  // visited rather than calling PreVisit/PostVisit.
80
  T WalkExponential(Regexp* re, T top_arg, int max_visits);
81
82
  // Clears the stack.  Should never be necessary, since
83
  // Walk always enters and exits with an empty stack.
84
  // Logs DFATAL if stack is not already clear.
85
  void Reset();
86
87
  // Returns whether walk was cut off.
88
7.43k
  bool stopped_early() { return stopped_early_; }
duckdb_re2::Regexp::Walker<duckdb_re2::Regexp*>::stopped_early()
Line
Count
Source
88
7.43k
  bool stopped_early() { return stopped_early_; }
Unexecuted instantiation: duckdb_re2::Regexp::Walker<int>::stopped_early()
89
90
 private:
91
  // Walk state for the entire traversal.
92
  std::stack<WalkState<T>> stack_;
93
  bool stopped_early_;
94
  int max_visits_;
95
96
  T WalkInternal(Regexp* re, T top_arg, bool use_copy);
97
98
  Walker(const Walker&) = delete;
99
  Walker& operator=(const Walker&) = delete;
100
};
101
102
template<typename T> T Regexp::Walker<T>::PreVisit(Regexp* re,
103
                                                   T parent_arg,
104
1.30M
                                                   bool* stop) {
105
1.30M
  return parent_arg;
106
1.30M
}
Unexecuted instantiation: duckdb_re2::Regexp::Walker<int>::PreVisit(duckdb_re2::Regexp*, int, bool*)
Unexecuted instantiation: duckdb_re2::Regexp::Walker<duckdb_re2::Frag>::PreVisit(duckdb_re2::Regexp*, duckdb_re2::Frag, bool*)
duckdb_re2::Regexp::Walker<duckdb_re2::Regexp*>::PreVisit(duckdb_re2::Regexp*, duckdb_re2::Regexp*, bool*)
Line
Count
Source
104
1.30M
                                                   bool* stop) {
105
1.30M
  return parent_arg;
106
1.30M
}
107
108
template<typename T> T Regexp::Walker<T>::PostVisit(Regexp* re,
109
                                                    T parent_arg,
110
                                                    T pre_arg,
111
                                                    T* child_args,
112
1.22M
                                                    int nchild_args) {
113
1.22M
  return pre_arg;
114
1.22M
}
duckdb_re2::Regexp::Walker<int>::PostVisit(duckdb_re2::Regexp*, int, int, int*, int)
Line
Count
Source
112
1.22M
                                                    int nchild_args) {
113
1.22M
  return pre_arg;
114
1.22M
}
Unexecuted instantiation: duckdb_re2::Regexp::Walker<duckdb_re2::Frag>::PostVisit(duckdb_re2::Regexp*, duckdb_re2::Frag, duckdb_re2::Frag, duckdb_re2::Frag*, int)
Unexecuted instantiation: duckdb_re2::Regexp::Walker<duckdb_re2::Regexp*>::PostVisit(duckdb_re2::Regexp*, duckdb_re2::Regexp*, duckdb_re2::Regexp*, duckdb_re2::Regexp**, int)
115
116
0
template<typename T> T Regexp::Walker<T>::Copy(T arg) {
117
0
  return arg;
118
0
}
Unexecuted instantiation: duckdb_re2::Regexp::Walker<int>::Copy(int)
Unexecuted instantiation: duckdb_re2::Regexp::Walker<duckdb_re2::Frag>::Copy(duckdb_re2::Frag)
Unexecuted instantiation: duckdb_re2::Regexp::Walker<duckdb_re2::Regexp*>::Copy(duckdb_re2::Regexp*)
119
120
// State about a single level in the traversal.
121
template<typename T> struct WalkState {
122
  WalkState(Regexp* re, T parent)
123
5.23M
    : re(re),
124
5.23M
      n(-1),
125
3.64M
      parent_arg(parent),
126
5.23M
      child_args(NULL) { }
duckdb_re2::WalkState<int>::WalkState(duckdb_re2::Regexp*, int)
Line
Count
Source
123
1.22M
    : re(re),
124
1.22M
      n(-1),
125
1.22M
      parent_arg(parent),
126
1.22M
      child_args(NULL) { }
duckdb_re2::WalkState<duckdb_re2::Frag>::WalkState(duckdb_re2::Regexp*, duckdb_re2::Frag)
Line
Count
Source
123
1.59M
    : re(re),
124
1.59M
      n(-1),
125
1.59M
      parent_arg(parent),
126
1.59M
      child_args(NULL) { }
duckdb_re2::WalkState<duckdb_re2::Regexp*>::WalkState(duckdb_re2::Regexp*, duckdb_re2::Regexp*)
Line
Count
Source
123
2.41M
    : re(re),
124
2.41M
      n(-1),
125
2.41M
      parent_arg(parent),
126
2.41M
      child_args(NULL) { }
127
128
  Regexp* re;  // The regexp
129
  int n;  // The index of the next child to process; -1 means need to PreVisit
130
  T parent_arg;  // Accumulated arguments.
131
  T pre_arg;
132
  T child_arg;  // One-element buffer for child_args.
133
  T* child_args;
134
};
135
136
14.8k
template<typename T> Regexp::Walker<T>::Walker() {
137
14.8k
  stopped_early_ = false;
138
14.8k
}
duckdb_re2::Regexp::Walker<int>::Walker()
Line
Count
Source
136
3.73k
template<typename T> Regexp::Walker<T>::Walker() {
137
3.73k
  stopped_early_ = false;
138
3.73k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Frag>::Walker()
Line
Count
Source
136
3.71k
template<typename T> Regexp::Walker<T>::Walker() {
137
3.71k
  stopped_early_ = false;
138
3.71k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Regexp*>::Walker()
Line
Count
Source
136
7.43k
template<typename T> Regexp::Walker<T>::Walker() {
137
7.43k
  stopped_early_ = false;
138
7.43k
}
139
140
14.8k
template<typename T> Regexp::Walker<T>::~Walker() {
141
14.8k
  Reset();
142
14.8k
}
duckdb_re2::Regexp::Walker<int>::~Walker()
Line
Count
Source
140
3.73k
template<typename T> Regexp::Walker<T>::~Walker() {
141
3.73k
  Reset();
142
3.73k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Frag>::~Walker()
Line
Count
Source
140
3.71k
template<typename T> Regexp::Walker<T>::~Walker() {
141
3.71k
  Reset();
142
3.71k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Regexp*>::~Walker()
Line
Count
Source
140
7.43k
template<typename T> Regexp::Walker<T>::~Walker() {
141
7.43k
  Reset();
142
7.43k
}
143
144
// Clears the stack.  Should never be necessary, since
145
// Walk always enters and exits with an empty stack.
146
// Logs DFATAL if stack is not already clear.
147
29.7k
template<typename T> void Regexp::Walker<T>::Reset() {
148
29.7k
  if (!stack_.empty()) {
149
0
    LOG(DFATAL) << "Stack not empty.";
150
0
    while (!stack_.empty()) {
151
0
      if (stack_.top().re->nsub_ > 1)
152
0
        delete[] stack_.top().child_args;
153
0
      stack_.pop();
154
0
    }
155
0
  }
156
29.7k
}
duckdb_re2::Regexp::Walker<int>::Reset()
Line
Count
Source
147
7.47k
template<typename T> void Regexp::Walker<T>::Reset() {
148
7.47k
  if (!stack_.empty()) {
149
0
    LOG(DFATAL) << "Stack not empty.";
150
0
    while (!stack_.empty()) {
151
0
      if (stack_.top().re->nsub_ > 1)
152
0
        delete[] stack_.top().child_args;
153
0
      stack_.pop();
154
0
    }
155
0
  }
156
7.47k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Frag>::Reset()
Line
Count
Source
147
7.43k
template<typename T> void Regexp::Walker<T>::Reset() {
148
7.43k
  if (!stack_.empty()) {
149
0
    LOG(DFATAL) << "Stack not empty.";
150
0
    while (!stack_.empty()) {
151
0
      if (stack_.top().re->nsub_ > 1)
152
0
        delete[] stack_.top().child_args;
153
0
      stack_.pop();
154
0
    }
155
0
  }
156
7.43k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Regexp*>::Reset()
Line
Count
Source
147
14.8k
template<typename T> void Regexp::Walker<T>::Reset() {
148
14.8k
  if (!stack_.empty()) {
149
0
    LOG(DFATAL) << "Stack not empty.";
150
0
    while (!stack_.empty()) {
151
0
      if (stack_.top().re->nsub_ > 1)
152
0
        delete[] stack_.top().child_args;
153
0
      stack_.pop();
154
0
    }
155
0
  }
156
14.8k
}
157
158
template<typename T> T Regexp::Walker<T>::WalkInternal(Regexp* re, T top_arg,
159
14.8k
                                                       bool use_copy) {
160
14.8k
  Reset();
161
162
14.8k
  if (re == NULL) {
163
0
    LOG(DFATAL) << "Walk NULL";
164
0
    return top_arg;
165
0
  }
166
167
14.8k
  stack_.push(WalkState<T>(re, top_arg));
168
169
14.8k
  WalkState<T>* s;
170
10.4M
  for (;;) {
171
10.4M
    T t;
172
10.4M
    s = &stack_.top();
173
10.4M
    re = s->re;
174
10.4M
    switch (s->n) {
175
5.23M
      case -1: {
176
5.23M
        if (--max_visits_ < 0) {
177
0
          stopped_early_ = true;
178
0
          t = ShortVisit(re, s->parent_arg);
179
0
          break;
180
0
        }
181
5.23M
        bool stop = false;
182
5.23M
        s->pre_arg = PreVisit(re, s->parent_arg, &stop);
183
5.23M
        if (stop) {
184
973k
          t = s->pre_arg;
185
973k
          break;
186
973k
        }
187
4.26M
        s->n = 0;
188
4.26M
        s->child_args = NULL;
189
4.26M
        if (re->nsub_ == 1)
190
274k
          s->child_args = &s->child_arg;
191
3.98M
        else if (re->nsub_ > 1)
192
266k
          s->child_args = new T[re->nsub_];
193
4.26M
        FALLTHROUGH_INTENDED;
194
4.26M
      }
195
9.48M
      default: {
196
9.48M
        if (re->nsub_ > 0) {
197
5.76M
          Regexp** sub = re->sub();
198
5.76M
          if (s->n < re->nsub_) {
199
5.22M
            if (use_copy && s->n > 0 && sub[s->n - 1] == sub[s->n]) {
200
0
              s->child_args[s->n] = Copy(s->child_args[s->n - 1]);
201
0
              s->n++;
202
5.22M
            } else {
203
5.22M
              stack_.push(WalkState<T>(sub[s->n], s->pre_arg));
204
5.22M
            }
205
5.22M
            continue;
206
5.22M
          }
207
5.76M
        }
208
209
4.26M
        t = PostVisit(re, s->parent_arg, s->pre_arg, s->child_args, s->n);
210
4.26M
        if (re->nsub_ > 1)
211
266k
          delete[] s->child_args;
212
4.26M
        break;
213
9.48M
      }
214
10.4M
    }
215
216
    // We've finished stack_.top().
217
    // Update next guy down.
218
5.23M
    stack_.pop();
219
5.23M
    if (stack_.empty())
220
14.8k
      return t;
221
5.22M
    s = &stack_.top();
222
5.22M
    if (s->child_args != NULL)
223
5.22M
      s->child_args[s->n] = t;
224
0
    else
225
0
      s->child_arg = t;
226
5.22M
    s->n++;
227
5.22M
  }
228
14.8k
}
duckdb_re2::Regexp::Walker<int>::WalkInternal(duckdb_re2::Regexp*, int, bool)
Line
Count
Source
159
3.73k
                                                       bool use_copy) {
160
3.73k
  Reset();
161
162
3.73k
  if (re == NULL) {
163
0
    LOG(DFATAL) << "Walk NULL";
164
0
    return top_arg;
165
0
  }
166
167
3.73k
  stack_.push(WalkState<T>(re, top_arg));
168
169
3.73k
  WalkState<T>* s;
170
2.45M
  for (;;) {
171
2.45M
    T t;
172
2.45M
    s = &stack_.top();
173
2.45M
    re = s->re;
174
2.45M
    switch (s->n) {
175
1.22M
      case -1: {
176
1.22M
        if (--max_visits_ < 0) {
177
0
          stopped_early_ = true;
178
0
          t = ShortVisit(re, s->parent_arg);
179
0
          break;
180
0
        }
181
1.22M
        bool stop = false;
182
1.22M
        s->pre_arg = PreVisit(re, s->parent_arg, &stop);
183
1.22M
        if (stop) {
184
0
          t = s->pre_arg;
185
0
          break;
186
0
        }
187
1.22M
        s->n = 0;
188
1.22M
        s->child_args = NULL;
189
1.22M
        if (re->nsub_ == 1)
190
72.7k
          s->child_args = &s->child_arg;
191
1.15M
        else if (re->nsub_ > 1)
192
47.5k
          s->child_args = new T[re->nsub_];
193
1.22M
        FALLTHROUGH_INTENDED;
194
1.22M
      }
195
2.45M
      default: {
196
2.45M
        if (re->nsub_ > 0) {
197
1.34M
          Regexp** sub = re->sub();
198
1.34M
          if (s->n < re->nsub_) {
199
1.22M
            if (use_copy && s->n > 0 && sub[s->n - 1] == sub[s->n]) {
200
0
              s->child_args[s->n] = Copy(s->child_args[s->n - 1]);
201
0
              s->n++;
202
1.22M
            } else {
203
1.22M
              stack_.push(WalkState<T>(sub[s->n], s->pre_arg));
204
1.22M
            }
205
1.22M
            continue;
206
1.22M
          }
207
1.34M
        }
208
209
1.22M
        t = PostVisit(re, s->parent_arg, s->pre_arg, s->child_args, s->n);
210
1.22M
        if (re->nsub_ > 1)
211
47.5k
          delete[] s->child_args;
212
1.22M
        break;
213
2.45M
      }
214
2.45M
    }
215
216
    // We've finished stack_.top().
217
    // Update next guy down.
218
1.22M
    stack_.pop();
219
1.22M
    if (stack_.empty())
220
3.73k
      return t;
221
1.22M
    s = &stack_.top();
222
1.22M
    if (s->child_args != NULL)
223
1.22M
      s->child_args[s->n] = t;
224
0
    else
225
0
      s->child_arg = t;
226
1.22M
    s->n++;
227
1.22M
  }
228
3.73k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Frag>::WalkInternal(duckdb_re2::Regexp*, duckdb_re2::Frag, bool)
Line
Count
Source
159
3.71k
                                                       bool use_copy) {
160
3.71k
  Reset();
161
162
3.71k
  if (re == NULL) {
163
0
    LOG(DFATAL) << "Walk NULL";
164
0
    return top_arg;
165
0
  }
166
167
3.71k
  stack_.push(WalkState<T>(re, top_arg));
168
169
3.71k
  WalkState<T>* s;
170
3.17M
  for (;;) {
171
3.17M
    T t;
172
3.17M
    s = &stack_.top();
173
3.17M
    re = s->re;
174
3.17M
    switch (s->n) {
175
1.59M
      case -1: {
176
1.59M
        if (--max_visits_ < 0) {
177
0
          stopped_early_ = true;
178
0
          t = ShortVisit(re, s->parent_arg);
179
0
          break;
180
0
        }
181
1.59M
        bool stop = false;
182
1.59M
        s->pre_arg = PreVisit(re, s->parent_arg, &stop);
183
1.59M
        if (stop) {
184
12.6k
          t = s->pre_arg;
185
12.6k
          break;
186
12.6k
        }
187
1.57M
        s->n = 0;
188
1.57M
        s->child_args = NULL;
189
1.57M
        if (re->nsub_ == 1)
190
73.5k
          s->child_args = &s->child_arg;
191
1.50M
        else if (re->nsub_ > 1)
192
120k
          s->child_args = new T[re->nsub_];
193
1.57M
        FALLTHROUGH_INTENDED;
194
1.57M
      }
195
3.16M
      default: {
196
3.16M
        if (re->nsub_ > 0) {
197
1.78M
          Regexp** sub = re->sub();
198
1.78M
          if (s->n < re->nsub_) {
199
1.58M
            if (use_copy && s->n > 0 && sub[s->n - 1] == sub[s->n]) {
200
0
              s->child_args[s->n] = Copy(s->child_args[s->n - 1]);
201
0
              s->n++;
202
1.58M
            } else {
203
1.58M
              stack_.push(WalkState<T>(sub[s->n], s->pre_arg));
204
1.58M
            }
205
1.58M
            continue;
206
1.58M
          }
207
1.78M
        }
208
209
1.57M
        t = PostVisit(re, s->parent_arg, s->pre_arg, s->child_args, s->n);
210
1.57M
        if (re->nsub_ > 1)
211
120k
          delete[] s->child_args;
212
1.57M
        break;
213
3.16M
      }
214
3.17M
    }
215
216
    // We've finished stack_.top().
217
    // Update next guy down.
218
1.59M
    stack_.pop();
219
1.59M
    if (stack_.empty())
220
3.71k
      return t;
221
1.58M
    s = &stack_.top();
222
1.58M
    if (s->child_args != NULL)
223
1.58M
      s->child_args[s->n] = t;
224
0
    else
225
0
      s->child_arg = t;
226
1.58M
    s->n++;
227
1.58M
  }
228
3.71k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Regexp*>::WalkInternal(duckdb_re2::Regexp*, duckdb_re2::Regexp*, bool)
Line
Count
Source
159
7.43k
                                                       bool use_copy) {
160
7.43k
  Reset();
161
162
7.43k
  if (re == NULL) {
163
0
    LOG(DFATAL) << "Walk NULL";
164
0
    return top_arg;
165
0
  }
166
167
7.43k
  stack_.push(WalkState<T>(re, top_arg));
168
169
7.43k
  WalkState<T>* s;
170
4.82M
  for (;;) {
171
4.82M
    T t;
172
4.82M
    s = &stack_.top();
173
4.82M
    re = s->re;
174
4.82M
    switch (s->n) {
175
2.41M
      case -1: {
176
2.41M
        if (--max_visits_ < 0) {
177
0
          stopped_early_ = true;
178
0
          t = ShortVisit(re, s->parent_arg);
179
0
          break;
180
0
        }
181
2.41M
        bool stop = false;
182
2.41M
        s->pre_arg = PreVisit(re, s->parent_arg, &stop);
183
2.41M
        if (stop) {
184
960k
          t = s->pre_arg;
185
960k
          break;
186
960k
        }
187
1.45M
        s->n = 0;
188
1.45M
        s->child_args = NULL;
189
1.45M
        if (re->nsub_ == 1)
190
128k
          s->child_args = &s->child_arg;
191
1.32M
        else if (re->nsub_ > 1)
192
98.0k
          s->child_args = new T[re->nsub_];
193
1.45M
        FALLTHROUGH_INTENDED;
194
1.45M
      }
195
3.86M
      default: {
196
3.86M
        if (re->nsub_ > 0) {
197
2.63M
          Regexp** sub = re->sub();
198
2.63M
          if (s->n < re->nsub_) {
199
2.40M
            if (use_copy && s->n > 0 && sub[s->n - 1] == sub[s->n]) {
200
0
              s->child_args[s->n] = Copy(s->child_args[s->n - 1]);
201
0
              s->n++;
202
2.40M
            } else {
203
2.40M
              stack_.push(WalkState<T>(sub[s->n], s->pre_arg));
204
2.40M
            }
205
2.40M
            continue;
206
2.40M
          }
207
2.63M
        }
208
209
1.45M
        t = PostVisit(re, s->parent_arg, s->pre_arg, s->child_args, s->n);
210
1.45M
        if (re->nsub_ > 1)
211
98.0k
          delete[] s->child_args;
212
1.45M
        break;
213
3.86M
      }
214
4.82M
    }
215
216
    // We've finished stack_.top().
217
    // Update next guy down.
218
2.41M
    stack_.pop();
219
2.41M
    if (stack_.empty())
220
7.43k
      return t;
221
2.40M
    s = &stack_.top();
222
2.40M
    if (s->child_args != NULL)
223
2.40M
      s->child_args[s->n] = t;
224
0
    else
225
0
      s->child_arg = t;
226
2.40M
    s->n++;
227
2.40M
  }
228
7.43k
}
229
230
11.1k
template<typename T> T Regexp::Walker<T>::Walk(Regexp* re, T top_arg) {
231
  // Without the exponential walking behavior,
232
  // this budget should be more than enough for any
233
  // regexp, and yet not enough to get us in trouble
234
  // as far as CPU time.
235
11.1k
  max_visits_ = 1000000;
236
11.1k
  return WalkInternal(re, top_arg, true);
237
11.1k
}
duckdb_re2::Regexp::Walker<int>::Walk(duckdb_re2::Regexp*, int)
Line
Count
Source
230
3.73k
template<typename T> T Regexp::Walker<T>::Walk(Regexp* re, T top_arg) {
231
  // Without the exponential walking behavior,
232
  // this budget should be more than enough for any
233
  // regexp, and yet not enough to get us in trouble
234
  // as far as CPU time.
235
3.73k
  max_visits_ = 1000000;
236
3.73k
  return WalkInternal(re, top_arg, true);
237
3.73k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Regexp*>::Walk(duckdb_re2::Regexp*, duckdb_re2::Regexp*)
Line
Count
Source
230
7.43k
template<typename T> T Regexp::Walker<T>::Walk(Regexp* re, T top_arg) {
231
  // Without the exponential walking behavior,
232
  // this budget should be more than enough for any
233
  // regexp, and yet not enough to get us in trouble
234
  // as far as CPU time.
235
7.43k
  max_visits_ = 1000000;
236
7.43k
  return WalkInternal(re, top_arg, true);
237
7.43k
}
238
239
template<typename T> T Regexp::Walker<T>::WalkExponential(Regexp* re, T top_arg,
240
3.71k
                                                          int max_visits) {
241
3.71k
  max_visits_ = max_visits;
242
3.71k
  return WalkInternal(re, top_arg, false);
243
3.71k
}
duckdb_re2::Regexp::Walker<duckdb_re2::Frag>::WalkExponential(duckdb_re2::Regexp*, duckdb_re2::Frag, int)
Line
Count
Source
240
3.71k
                                                          int max_visits) {
241
3.71k
  max_visits_ = max_visits;
242
3.71k
  return WalkInternal(re, top_arg, false);
243
3.71k
}
Unexecuted instantiation: duckdb_re2::Regexp::Walker<int>::WalkExponential(duckdb_re2::Regexp*, int, int)
244
245
}  // namespace re2
246
247
#endif  // RE2_WALKER_INL_H_