[libcxx-commits] [libcxx] [libc++] Rewrite std::regex (PR #217680)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Aug 21 07:47:40 PDT 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/217680
>From ebc8633ef43e034580ce83825a7f2df150b24e44 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 25 Mar 2026 03:36:58 +0100
Subject: [PATCH 01/21] [libc++] Avoid a bunch of allocations when using
std::regex_search
---
libcxx/include/regex | 33 +++++++++++------
libcxx/test/benchmarks/regex.bench.cpp | 51 ++++++++++++++++++++++++++
2 files changed, 72 insertions(+), 12 deletions(-)
create mode 100644 libcxx/test/benchmarks/regex.bench.cpp
diff --git a/libcxx/include/regex b/libcxx/include/regex
index a11635093ec2b..0be8b4703c725 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -2615,13 +2615,16 @@ private:
regex_constants::match_flag_type __flags) const;
template <class _Allocator>
- bool __match_at_start(const _CharT* __first,
- const _CharT* __last,
- match_results<const _CharT*, _Allocator>& __m,
- regex_constants::match_flag_type __flags,
- bool) const;
+ bool __match_at_start(
+ vector<__state>& __states,
+ const _CharT* __first,
+ const _CharT* __last,
+ match_results<const _CharT*, _Allocator>& __m,
+ regex_constants::match_flag_type __flags,
+ bool) const;
template <class _Allocator>
bool __match_at_start_ecma(
+ vector<__state>& __states,
const _CharT* __first,
const _CharT* __last,
match_results<const _CharT*, _Allocator>& __m,
@@ -2636,6 +2639,7 @@ private:
bool) const;
template <class _Allocator>
bool __match_at_start_posix_subs(
+ vector<__state>& __states,
const _CharT* __first,
const _CharT* __last,
match_results<const _CharT*, _Allocator>& __m,
@@ -2758,7 +2762,9 @@ template <class _CharT, class _Traits>
void __lookahead<_CharT, _Traits>::__exec(__state& __s) const {
match_results<const _CharT*> __m;
__m.__init(1 + __exp_.mark_count(), __s.__current_, __s.__last_);
+ vector<__state> __states_buffer;
bool __matched = __exp_.__match_at_start_ecma(
+ __states_buffer,
__s.__current_,
__s.__last_,
__m,
@@ -4880,12 +4886,13 @@ swap(match_results<_BidirectionalIterator, _Allocator>& __x, match_results<_Bidi
template <class _CharT, class _Traits>
template <class _Allocator>
bool basic_regex<_CharT, _Traits>::__match_at_start_ecma(
+ vector<__state>& __states,
const _CharT* __first,
const _CharT* __last,
match_results<const _CharT*, _Allocator>& __m,
regex_constants::match_flag_type __flags,
bool __at_first) const {
- vector<__state> __states;
+ __states.clear();
__node* __st = __start_.get();
if (__st) {
sub_match<const _CharT*> __unmatched;
@@ -5036,12 +5043,12 @@ bool basic_regex<_CharT, _Traits>::__match_at_start_posix_nosubs(
template <class _CharT, class _Traits>
template <class _Allocator>
bool basic_regex<_CharT, _Traits>::__match_at_start_posix_subs(
+ vector<__state>& __states,
const _CharT* __first,
const _CharT* __last,
match_results<const _CharT*, _Allocator>& __m,
regex_constants::match_flag_type __flags,
bool __at_first) const {
- vector<__state> __states;
__state __best_state;
ptrdiff_t __highest_j = 0;
ptrdiff_t __np = std::distance(__first, __last);
@@ -5125,16 +5132,17 @@ bool basic_regex<_CharT, _Traits>::__match_at_start_posix_subs(
template <class _CharT, class _Traits>
template <class _Allocator>
bool basic_regex<_CharT, _Traits>::__match_at_start(
+ vector<__state>& __states,
const _CharT* __first,
const _CharT* __last,
match_results<const _CharT*, _Allocator>& __m,
regex_constants::match_flag_type __flags,
bool __at_first) const {
if (__get_grammar(__flags_) == ECMAScript)
- return __match_at_start_ecma(__first, __last, __m, __flags, __at_first);
+ return __match_at_start_ecma(__states, __first, __last, __m, __flags, __at_first);
if (mark_count() == 0)
return __match_at_start_posix_nosubs(__first, __last, __m, __flags, __at_first);
- return __match_at_start_posix_subs(__first, __last, __m, __flags, __at_first);
+ return __match_at_start_posix_subs(__states, __first, __last, __m, __flags, __at_first);
}
template <class _CharT, class _Traits>
@@ -5147,8 +5155,9 @@ bool basic_regex<_CharT, _Traits>::__search(
if (__flags & regex_constants::match_prev_avail)
__flags &= ~(regex_constants::match_not_bol | regex_constants::match_not_bow);
+ vector<__state> __states_buffer;
__m.__init(1 + mark_count(), __first, __last, __flags & regex_constants::__no_update_pos);
- if (__match_at_start(__first, __last, __m, __flags, !(__flags & regex_constants::__no_update_pos))) {
+ if (__match_at_start(__states_buffer, __first, __last, __m, __flags, !(__flags & regex_constants::__no_update_pos))) {
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
__m.__suffix_.first = __m[0].second;
@@ -5159,7 +5168,7 @@ bool basic_regex<_CharT, _Traits>::__search(
__flags |= regex_constants::match_prev_avail;
for (++__first; __first != __last; ++__first) {
__m.__matches_.assign(__m.size(), __m.__unmatched_);
- if (__match_at_start(__first, __last, __m, __flags, false)) {
+ if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false)) {
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
__m.__suffix_.first = __m[0].second;
@@ -5169,7 +5178,7 @@ bool basic_regex<_CharT, _Traits>::__search(
__m.__matches_.assign(__m.size(), __m.__unmatched_);
}
__m.__matches_.assign(__m.size(), __m.__unmatched_);
- if (__match_at_start(__first, __last, __m, __flags, false)) {
+ if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false)) {
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
__m.__suffix_.first = __m[0].second;
diff --git a/libcxx/test/benchmarks/regex.bench.cpp b/libcxx/test/benchmarks/regex.bench.cpp
new file mode 100644
index 0000000000000..8b218843dedc1
--- /dev/null
+++ b/libcxx/test/benchmarks/regex.bench.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+
+#include <regex>
+
+#include "benchmark/benchmark.h"
+#include "GenerateInput.h"
+
+template <std::regex_constants::syntax_option_type Arg>
+static void BM_regex_construct(benchmark::State& state) {
+ static std::string_view regexes[] = {".*[abcdefghijklmnopqrtuvwxyz]{10,100}", "This is technically a regex."};
+ while (state.KeepRunningBatch(std::size(regexes))) {
+ for (auto& reg : regexes)
+ std::regex r(reg.data(), Arg);
+ }
+}
+BENCHMARK(BM_regex_construct<std::regex::basic>);
+BENCHMARK(BM_regex_construct<std::regex::extended>);
+BENCHMARK(BM_regex_construct<std::regex::awk>);
+BENCHMARK(BM_regex_construct<std::regex::ECMAScript>);
+
+static void BM_regex_run_bad_match(benchmark::State& state) {
+ std::regex r("This is technically a regex.");
+ std::string input = getRandomString(1 << 16);
+
+ for (auto _ : state) {
+ std::regex_search(input, r);
+ }
+}
+BENCHMARK(BM_regex_run_bad_match);
+
+static void BM_regex_run_almost_match(benchmark::State& state) {
+ std::regex r("This is technically a regex.");
+ std::string input;
+ for (size_t i = 0; i != 2500; ++i)
+ input += "This is technically a rege";
+
+ for (auto _ : state) {
+ std::regex_search(input, r);
+ }
+}
+BENCHMARK(BM_regex_run_almost_match);
+
+BENCHMARK_MAIN();
>From 428ae06634d08fbe0dd0b19fb6bcf9487a1bc857 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 25 Feb 2026 10:06:15 +0100
Subject: [PATCH 02/21] [libc++] A new regex implementation
---
libcxx/include/CMakeLists.txt | 4 +
libcxx/include/__regex/basic_parser.h | 262 +++++++++
libcxx/include/__regex/ecma_parser.h | 240 ++++++++
libcxx/include/__regex/interpreter.h | 555 ++++++++++++++++++
libcxx/include/__regex/parser_common.h | 276 +++++++++
libcxx/include/__regex/regex_error.h | 176 ++++++
libcxx/include/regex | 555 ++----------------
.../re/re.alg/re.alg.search/basic.pass.cpp | 12 +
.../re.grammar/excessive_brace_count.pass.cpp | 3 +-
9 files changed, 1564 insertions(+), 519 deletions(-)
create mode 100644 libcxx/include/__regex/basic_parser.h
create mode 100644 libcxx/include/__regex/ecma_parser.h
create mode 100644 libcxx/include/__regex/interpreter.h
create mode 100644 libcxx/include/__regex/parser_common.h
create mode 100644 libcxx/include/__regex/regex_error.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index a1d6a09aa6b20..1178b29eaedbe 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -794,6 +794,10 @@ set(files
__ranges/views.h
__ranges/zip_transform_view.h
__ranges/zip_view.h
+ __regex/basic_parser.h
+ __regex/interpreter.h
+ __regex/parser_common.h
+ __regex/regex_error.h
__split_buffer
__std_mbstate_t.h
__stop_token/atomic_unique_lock.h
diff --git a/libcxx/include/__regex/basic_parser.h b/libcxx/include/__regex/basic_parser.h
new file mode 100644
index 0000000000000..d32b957557fc6
--- /dev/null
+++ b/libcxx/include/__regex/basic_parser.h
@@ -0,0 +1,262 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___REGEX_BASIC_PARSER_H
+#define _LIBCPP___REGEX_BASIC_PARSER_H
+
+#include <__algorithm/search.h>
+#include <__config>
+#include <__iterator/next.h>
+#include <__regex/interpreter.h>
+#include <__regex/parser_common.h>
+#include <__regex/regex_error.h>
+#include <__utility/exchange.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace __regex::__basic::inline __preserve_none {
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+class __parser {
+ __interpreter<_CharT, _Traits> __machine_;
+ _ForwardIterator __first_;
+ _ForwardIterator __last_;
+ regex_constants::syntax_option_type __flags_ = regex_constants::syntax_option_type();
+ uint8_t __marked_count_ = 0;
+
+ bool __parse_ord_char(_ForwardIterator& __first, _ForwardIterator __last) {
+ _LIBCPP_ASSERT_INTERNAL(__first != __last, "Expected parseable character");
+ auto __next = std::next(__first);
+ if (__next == __last && *__first == '$')
+ return false;
+ if (*__first == '.' || *__first == '\\' || *__first == '[')
+ return false;
+ __machine_.__push_char_matcher(*__first, __flags_);
+ __first = __next;
+ return true;
+ }
+
+ bool __parse_quoted_char() {
+ _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "Expected parseable character");
+ auto __next = std::next(__first_);
+ if (__next == __last_)
+ return false;
+ if (*__first_ != '\\')
+ return false;
+ switch (*__next) {
+ case '^':
+ case '.':
+ case '*':
+ case '[':
+ case '$':
+ case '\\':
+ __machine_.__push_char_matcher(*__next, __flags_);
+ __first_ = ++__next;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool __parse_one_char_or_coll_elem() {
+ if (__first_ == __last_)
+ return false;
+
+ if (__parse_ord_char(__first_, __last_))
+ return true;
+ if (__parse_quoted_char())
+ return true;
+
+ if (*__first_ == '.') {
+ __machine_.__push_any_matcher();
+ ++__first_;
+ return true;
+ } else {
+ return __regex::__parse_bracket_expression(__machine_, __first_, __last_, __flags_);
+ }
+ }
+
+ bool __parse_backref() {
+ if (__first_ == __last_)
+ return false;
+
+ auto __next = std::next(__first_);
+ if (__next == __last_)
+ return false;
+ if (*__first_ != '\\' || *__next < '0' || *__next > '9')
+ return false;
+ if (*__next == '0') {
+ __machine_.__push_char_matcher('\0');
+ __first_ = ++__next;
+ return true;
+ }
+ auto __val = *__next - '0';
+ if (__val > __marked_count_)
+ std::__throw_regex_error<regex_constants::error_backref>();
+ __machine_.__push_backref_matcher(__val, __flags_);
+ __first_ = ++__next;
+ return true;
+ }
+
+ bool __parse_escaped_character(_CharT __char) {
+ if (__first_ == __last_)
+ return false;
+ auto __next = std::next(__first_);
+ if (__next == __last_)
+ return false;
+ if (*__first_ != '\\' || *__next != __char)
+ return false;
+ __first_ = ++__next;
+ return true;
+ }
+
+ bool __parse_nondupl() {
+ if (__parse_one_char_or_coll_elem())
+ return true;
+
+ if (__parse_escaped_character('(')) {
+ size_t __subexpr_num = __marked_count_++;
+ __machine_.__push_subexpression_begin(__subexpr_num);
+ __parse_re_expression();
+ if (!__parse_escaped_character(')'))
+ std::__throw_regex_error<regex_constants::error_paren>();
+ __machine_.__push_subexpression_end(__subexpr_num);
+ return true;
+ } else {
+ return __parse_backref();
+ }
+ }
+
+ bool __parse_dupl_symbol(size_t __expr_start) {
+ if (__first_ == __last_)
+ return false;
+
+ if (*__first_ == '*') {
+ __machine_.__push_n_to_m_matcher(__expr_start, 0, numeric_limits<size_t>::max());
+ ++__first_;
+ return true;
+ }
+
+ if (!__parse_escaped_character('{'))
+ return false;
+
+ size_t __min;
+ if (auto __res = __regex::__parse_dup_count(__first_, __last_)) {
+ __min = __res.__num_;
+ } else {
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ }
+
+ if (__first_ == __last_)
+ std::__throw_regex_error<regex_constants::error_brace>();
+ if (*__first_ == ',') {
+ ++__first_;
+ size_t __max;
+ if (auto __res = __regex::__parse_dup_count(__first_, __last_)) {
+ __max = __res.__num_;
+ } else {
+ __max = numeric_limits<size_t>::max();
+ }
+
+ if (__max < __min || !__parse_escaped_character('}'))
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ __machine_.__push_n_to_m_matcher(__expr_start, __min, __max);
+ return true;
+ }
+
+ if (!__parse_escaped_character('}'))
+ std::__throw_regex_error<regex_constants::error_brace>();
+ __machine_.__push_n_matcher(__expr_start, __min);
+ return true;
+ }
+
+ bool __parse_simple_re() {
+ if (__first_ == __last_)
+ return false;
+
+ auto __expr_start = __machine_.size();
+ if (__parse_nondupl()) {
+ __parse_dupl_symbol(__expr_start);
+ return true;
+ }
+ return false;
+ }
+
+ void __parse_re_expression() {
+ while (__parse_simple_re())
+ ;
+ }
+
+ void __parse_basic_expr() {
+ if (__first_ == __last_)
+ return;
+
+ if (*__first_ == '^') {
+ __machine_.__push_start_anchor();
+ ++__first_;
+ if (__first_ == __last_)
+ return;
+ }
+
+ __parse_re_expression();
+
+ if (__first_ != __last_) {
+ auto __next = std::next(__first_);
+ if (__next == __last_ && *__first_ == '$') {
+ __machine_.__push_end_anchor();
+ __first_ = __next;
+ }
+ }
+
+ if (__first_ != __last_)
+ std::__throw_regex_error<regex_constants::__re_err_empty>();
+ }
+
+public:
+ __parser(
+ _ForwardIterator __first, _ForwardIterator __last, _Traits __traits, regex_constants::syntax_option_type __flags)
+ : __machine_(__traits), __first_(__first), __last_(__last), __flags_(__flags) {}
+
+ void __parse_basic() {
+ __parse_basic_expr();
+ __machine_.__push_end_state();
+ }
+
+ void __parse_grep() {
+ auto __newline = std::find(__first_, __last_, '\n');
+ if (__newline != __first_) {
+ std::swap(__last_, __newline);
+ __parse_basic_expr();
+ std::swap(__last_, __newline);
+ if (__first_ != __newline)
+ std::__throw_regex_error<regex_constants::__re_err_grammar>();
+ }
+ if (__first_ != __last_)
+ ++__first_;
+ while (__first_ != __last_) {
+ __newline = std::find(__first_, __last_, '\n');
+ std::swap(__last_, __newline);
+ __parse_basic_expr();
+ std::swap(__last_, __newline);
+ if (__first_ != __newline)
+ std::__throw_regex_error<regex_constants::__re_err_grammar>();
+ __machine_.__push_alternative(0, __machine_.size());
+ if (__first_ != __last_)
+ ++__first_;
+ }
+ __machine_.__push_end_state();
+ }
+
+ __interpreter<_CharT, _Traits> __extract_interpreter() { return std::move(__machine_); }
+ size_t mark_count() const { return __marked_count_; }
+};
+} // namespace __regex::__basic::inline __preserve_none
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___REGEX_BASIC_PARSER_H
diff --git a/libcxx/include/__regex/ecma_parser.h b/libcxx/include/__regex/ecma_parser.h
new file mode 100644
index 0000000000000..06fcf75db68ca
--- /dev/null
+++ b/libcxx/include/__regex/ecma_parser.h
@@ -0,0 +1,240 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___REGEX_ECMA_PARSER_H
+#define _LIBCPP___REGEX_ECMA_PARSER_H
+
+#include <__config>
+#include <__regex/regex_error.h>
+#include <__regex/state_machine.h>
+
+#define _LIBCPP_PARSER_FUNCTION [[clang::preserve_none]]
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace __regex::__ecma {
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION bool
+__parse_disjunction(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last);
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION bool
+__parse_assertion(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ if (__first == __last)
+ return false;
+ switch (*__first) {
+ case '^': {
+ __machine.push_back(__state::__start_anchor);
+ ++__first;
+ return true;
+ }
+ case '$': {
+ __machine.push_back(__state::__end_anchor);
+ ++__first;
+ return true;
+ }
+ case '\\': {
+ auto __next = std::next(__first);
+ if (__next == __last)
+ return false;
+ if (auto __char = *__next; __char == 'b' || __char == 'B') {
+ __machine.push_back(__char == 'b' ? __state::__match_word_boundary : __state::__match_no_word_boundary);
+ __first = ++__next;
+ return true;
+ }
+ return false;
+ }
+ case '(': {
+ auto __next = std::next(__first);
+ if (__next == __last || *++__next != '?' || __next == __last)
+ return false;
+ auto __char = *__next;
+ if (__char != '=' && __char != '!')
+ return false;
+ __machine.push_back(__char == '=' ? __state::__positive_lookahead_start : __state::__negative_lookahead_start);
+ if (!__ecma::__parse_disjunction(__machine, __first, __last))
+ return false;
+ __machine.push_back(__state::__lookahead_end);
+ if (__first == __last || *__first++ != ')')
+ std::__throw_regex_error<regex_constants::error_paren>();
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION bool
+__parse_decimal_escape(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ if (*__first == '0') {
+ __regex::__match_char(__machine, '\0');
+ ++__first;
+ return true;
+ }
+
+ if ('1' <= *__first && *__first <= '9') {
+ unsigned __value = *__first - '0';
+ for (++__first; __first != __last && '0' <= *__first && *__first <= '9'; ++__first) {
+ if (__value >= numeric_limits<unsigned>::max() / 10)
+ std::__throw_regex_error<regex_constants::error_backref>();
+ __value = __value * 10 + *__first - '0';
+ }
+ if (__value == 0)
+ std::__throw_regex_error<regex_constants::error_backref>();
+ __machine.push_back(__state::__match_backref);
+ __regex::__write_uleb(__machine, __value);
+ }
+ return true;
+}
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION bool
+__parse_character_class_escape(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ if (__first == __last)
+ return false;
+ switch (*__first) {
+ case 'd':
+ __machine.push_back(__state::__match_digits);
+ break;
+ case 'D':
+ __machine.push_back(__state::__match_no_digits);
+ break;
+ case 's':
+ __machine.push_back(__state::__match_whitespace);
+ break;
+ case 'S':
+ __machine.push_back(__state::__match_no_whitespace);
+ break;
+ case 'w':
+ __machine.push_back(__state::__match_word_character);
+ break;
+ case 'W':
+ __machine.push_back(__state::__match_no_word_character);
+ break;
+ default:
+ return false;
+ }
+ ++__first;
+ return true;
+}
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION bool
+__parse_character_escape(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ if (__first == __last)
+ return false;
+ switch (*__first) {
+ case 'f':
+ __regex::__match_char(__machine, '\f');
+ break;
+ case 'n':
+ __regex::__match_char(__machine, '\n');
+ break;
+ case 'r':
+ __regex::__match_char(__machine, '\r');
+ break;
+ case 't':
+ __regex::__match_char(__machine, '\t');
+ break;
+ case 'v':
+ __regex::__match_char(__machine, '\v');
+ break;
+
+ case 'c': {
+ auto __next = std::next(__first);
+ if (__next == __last)
+ std::__throw_regex_error<regex_constants::error_escape>();
+ if (('A' <= *__next && *__next <= 'Z') || ('a' <= *__next && *__next <= 'z')) {
+ __regex::__match_char(__machine, *__next % 32);
+ __first += ++__next;
+ } else {
+ std::__throw_regex_error<regex_constants::error_escape>();
+ }
+ }
+ }
+ ++__first;
+ return true;
+}
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION bool
+__parse_atom_escape(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ _LIBCPP_ASSERT_INTERNAL(*__first == '\\', "Parsing escape character without an escape start?");
+ auto __next = std::next(__first);
+ if (__next == __last)
+ std::__throw_regex_error<regex_constants::error_escape>();
+
+ if (__ecma::__parse_decimal_escape(__machine, __next, __last) ||
+ __ecma::__parse_character_class_escape(__machine, __next, __last)) {
+ __first = __next;
+ return true;
+ }
+ return false;
+}
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION bool
+__parse_atom(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ if (__first == __last)
+ return false;
+
+ switch (*__first) {
+ case '.': {
+ __machine.push_back(__state::__match_any);
+ ++__first;
+ return true;
+ }
+ case '\\':
+ return __ecma::__parse_atom_escape(__machine, __first, __last);
+ }
+
+ return false;
+}
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION bool
+__parse_term(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ return __ecma::__parse_assertion(__machine, __first, __last) || __ecma::__parse_atom(__machine, __first, __last);
+}
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION void
+__parse_alternative(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ while (true) {
+ __ecma::__parse_term(__machine, __first, __last);
+ }
+}
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION bool
+__parse_disjunction(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ while (__first != __last) {
+ __ecma::__parse_alternative(__machine, __first, __last);
+ }
+ return true;
+}
+
+template <class _ForwardIterator>
+_LIBCPP_PARSER_FUNCTION void
+__parse_pattern(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ __ecma::__parse_disjunction(__machine, __first, __last);
+}
+
+template <class _ForwardIterator>
+__state_machine __parse(_ForwardIterator __first, _ForwardIterator __last) {
+ __state_machine __machine;
+
+ __ecma::__parse_pattern(__machine, __first, __last);
+
+ return __machine;
+}
+} // namespace __regex::__ecma
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___REGEX_ECMA_PARSER_H
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
new file mode 100644
index 0000000000000..515ce2cca3e08
--- /dev/null
+++ b/libcxx/include/__regex/interpreter.h
@@ -0,0 +1,555 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___REGEX_INTERPRETER_H
+#define _LIBCPP___REGEX_INTERPRETER_H
+
+#include <__algorithm/copy_if.h>
+#include <__algorithm/equal.h>
+#include <__algorithm/min.h>
+#include <__algorithm/reverse.h>
+#include <__algorithm/transform.h>
+#include <__config>
+#include <__iterator/back_insert_iterator.h>
+#include <__ranges/filter_view.h>
+#include <__ranges/views.h>
+#include <__regex/regex_error.h>
+#include <__utility/pair.h>
+#include <__utility/to_underlying.h>
+#include <__vector/vector.h>
+#include <stack>
+#include <string_view>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _CharT>
+class __node;
+
+template <class _BidirectionalIterator>
+class sub_match;
+
+template <class _BidirectionalIterator, class _Allocator = allocator<sub_match<_BidirectionalIterator> > >
+class match_results;
+
+template <class _CharT>
+struct __state {
+ enum __states {
+ __end_state = -1000,
+ __consume_input, // -999
+ __begin_marked_expr, // -998
+ __end_marked_expr, // -997
+ __pop_state, // -996
+ __accept_and_consume, // -995
+ __accept_but_not_consume, // -994
+ __reject, // -993
+ __split,
+ __repeat
+ };
+
+ int __do_;
+ const _CharT* __first_;
+ const _CharT* __current_;
+ const _CharT* __last_;
+ vector<sub_match<const _CharT*> > __sub_matches_;
+ vector<pair<size_t, const _CharT*> > __loop_data_;
+ const __node<_CharT>* __node_;
+ regex_constants::match_flag_type __flags_;
+ bool __at_first_;
+
+ _LIBCPP_HIDE_FROM_ABI __state()
+ : __do_(0),
+ __first_(nullptr),
+ __current_(nullptr),
+ __last_(nullptr),
+ __node_(nullptr),
+ __flags_(),
+ __at_first_(false) {}
+};
+
+namespace __regex {
+enum class __state : uint8_t {
+ __start_anchor,
+ __end_anchor,
+ __branch_alternative,
+ __match_any,
+ __match_char,
+ __match_icase_char,
+ __match_backref,
+ __match_icase_backref,
+ __match_character_list,
+ __match_no_character_list,
+ __marked_subexpression_begin,
+ __marked_subexpression_end,
+ __branch_n_to_m_matcher,
+ __match_n_to_m_times,
+ __match_n_times,
+ __relative_jump,
+ __end_state,
+};
+
+template <class _CharT>
+union __interpreter_info {
+ __interpreter_info(__state __st) : __state_(__st) {}
+ __interpreter_info(_CharT __c) : __char_(__c) {}
+ __interpreter_info(uint8_t __int) : __int_(__int) {}
+
+ template <class _Tp>
+ __interpreter_info(_Tp) = delete;
+
+ __state __state_;
+ _CharT __char_;
+ uint8_t __int_;
+};
+
+static_assert(sizeof(__interpreter_info<char>) == 1);
+
+template <class _CharT, class _Traits>
+struct __bracket_expr {
+ vector<_CharT> __chars_;
+ vector<_CharT> __digraphs_;
+ vector<_CharT> __ranges_;
+ vector<typename _Traits::string_type> __equivalences_;
+ typename _Traits::char_class_type __mask_ = 0;
+};
+
+template <class _CharT, class _Traits>
+class __interpreter {
+ vector<__interpreter_info<_CharT> > __machine_;
+ vector<size_t> __initial_loop_values_;
+ _Traits __traits_;
+
+ static size_t __read_uleb(const vector<__interpreter_info<_CharT> >& __machine, size_t& __current_pos) {
+ size_t __result = 0;
+ size_t __shift = 0;
+
+ uint8_t __byte;
+ do {
+ __byte = __machine[__current_pos++].__int_;
+ __result |= (__byte & 0x7f) << __shift;
+ __shift += 7;
+ } while (__byte & 0x80);
+ return __result;
+ }
+
+ struct __global_execution_state {
+ struct __local_execution_state {
+ const _CharT* __current_;
+ vector<sub_match<const _CharT*> > __sub_matches_;
+ size_t __current_pos_;
+ vector<size_t> __loop_values_;
+ vector<const _CharT*> __loop_starts_;
+
+ bool __execute(const _CharT* __first, const _CharT* __last, __global_execution_state& __gstate) {
+ while (true) {
+ auto __st = __gstate.__machine()[__current_pos_++].__state_;
+ switch (__st) {
+ using enum __state;
+
+ case __start_anchor: {
+ if (!__gstate.__at_first_ || __first != __current_)
+ return false;
+ } break;
+
+ case __end_anchor: {
+ if (__current_ != __last)
+ return false;
+ } break;
+
+ case __end_state: {
+ return true;
+ }
+
+ case __match_any: {
+ if (__current_ == __last)
+ return false;
+ ++__current_;
+ } break;
+
+ case __match_char: {
+ if (__current_ == __last || *__current_ != __gstate.__machine()[__current_pos_++].__char_)
+ return false;
+ ++__current_;
+ } break;
+
+ case __match_icase_char: {
+ if (__current_ == __last || __gstate.__machine_.__traits_.translate_nocase(*__current_) !=
+ __gstate.__machine()[__current_pos_++].__char_)
+ return false;
+ ++__current_;
+ } break;
+
+ case __branch_alternative: {
+ auto __offset = __read_uleb(__gstate.__machine(), __current_pos_);
+ auto __cpy = *this;
+ __cpy.__current_pos_ += __offset;
+ __gstate.__states_.push(std::move(__cpy));
+ break;
+ }
+
+ case __relative_jump: {
+ __current_pos_ += __read_uleb(__gstate.__machine(), __current_pos_);
+ break;
+ }
+
+ case __branch_n_to_m_matcher: {
+ auto __loop_index = __read_uleb(__gstate.__machine(), __current_pos_);
+ auto __again_pos_base = __current_pos_;
+ auto __again_pos = __again_pos_base - __read_uleb(__gstate.__machine(), __current_pos_);
+ if (__loop_values_[__loop_index] > 0) {
+ --__loop_values_[__loop_index];
+ __current_pos_ = __again_pos;
+ break;
+ }
+ if (__loop_starts_[__loop_index] != __current_ && __loop_values_[__loop_index + 1] > 0) {
+ --__loop_values_[__loop_index + 1];
+ __loop_starts_[__loop_index] = __current_;
+ __gstate.__states_.push(*this);
+ __current_pos_ = __again_pos;
+ break;
+ }
+ break;
+ }
+
+ case __match_backref: {
+ sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__gstate.__machine(), __current_pos_) - 1];
+ if (!__match.matched)
+ return false;
+
+ auto __len = __match.second - __match.first;
+ if (__last - __current_ < __len || !std::equal(__match.first, __match.second, __current_))
+ return false;
+
+ __current_ += __len;
+ } break;
+
+ case __match_icase_backref: {
+ sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__gstate.__machine(), __current_pos_) - 1];
+ if (!__match.matched)
+ return false;
+
+ auto __len = __match.second - __match.first;
+ if (__last - __current_ < __len)
+ return false;
+
+ for (ptrdiff_t __i = 0; __i != __len; ++__i) {
+ if (__gstate.__machine_.__traits_.translate_nocase(__match.first[__i]) !=
+ __gstate.__machine_.__traits_.translate_nocase(__current_[__i]))
+ return false;
+ }
+
+ __current_ += __len;
+ } break;
+
+ case __match_character_list:
+ case __match_no_character_list: {
+ if (__current_ == __last)
+ return false;
+ static const auto __buffer_size =
+ std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1));
+ _CharT __buffer[__buffer_size];
+ for (size_t __i = 0; __i != __buffer_size; ++__i)
+ __buffer[__i] = __gstate.__machine()[__current_pos_++].__char_;
+ typename _Traits::char_class_type __mask;
+ __builtin_memcpy(&__mask, __buffer, sizeof(typename _Traits::char_class_type));
+
+ auto __chars = __read_uleb(__gstate.__machine(), __current_pos_);
+ auto __digraphs = __read_uleb(__gstate.__machine(), __current_pos_) * 2;
+ auto __ranges = __read_uleb(__gstate.__machine(), __current_pos_) * 4;
+ auto __equiv_count = __read_uleb(__gstate.__machine(), __current_pos_);
+ auto __equiv_size = __read_uleb(__gstate.__machine(), __current_pos_);
+
+ bool __found = false;
+
+ for (size_t __i = 0; __i != __chars; ++__i) {
+ if (__gstate.__machine()[__current_pos_ + __i].__char_ == *__current_) {
+ __found = true;
+ break;
+ }
+ }
+
+ __current_pos_ += __chars;
+
+ if (__found) {
+ __current_pos_ += __digraphs + __ranges + __equiv_size;
+ ++__current_;
+ if (__st == __match_no_character_list)
+ return false;
+ break;
+ }
+
+ if (__current_ + 1 != __last) {
+ _CharT __vals[2] = {__current_[0], __current_[1]};
+
+ for (size_t __i = 0; __i != __digraphs; __i += 2) {
+ if (__gstate.__machine()[__current_pos_ + __i].__char_ == __vals[0] &&
+ __gstate.__machine()[__current_pos_ + __i + 1].__char_ == __vals[1]) {
+ __found = true;
+ break;
+ }
+ }
+ }
+
+ __current_pos_ += __digraphs;
+
+ if (__found) {
+ __current_pos_ += __ranges + __equiv_size;
+ __current_ += 2;
+ if (__st == __match_no_character_list)
+ return false;
+ break;
+ }
+
+ auto __cmp = __gstate.__machine_.__traits_.transform(__current_, __current_ + 1);
+ for (size_t __i = 0; __i != __ranges; __i += 4) {
+ _CharT __range_info[4];
+ std::transform(__gstate.__machine_.__machine_.begin() + __current_pos_ + __i,
+ __gstate.__machine_.__machine_.begin() + __current_pos_ + __i + 4,
+ __range_info,
+ [](__interpreter_info<_CharT> __val) { return __val.__char_; });
+ basic_string_view<_CharT> __min(__range_info, __range_info[1] == '\0' ? 1 : 2);
+ basic_string_view<_CharT> __max(__range_info + 2, __range_info[3] == '\0' ? 1 : 2);
+ if (__min <= __cmp && __cmp <= __max) {
+ __found = true;
+ __current_ += __cmp.size();
+ break;
+ }
+ }
+
+ __current_pos_ += __ranges;
+
+ if (__found) {
+ __current_pos_ += __equiv_size;
+ if (__st == __match_no_character_list)
+ return false;
+ break;
+ }
+
+ if (__gstate.__machine_.__traits_.isctype(*__current_, __mask)) {
+ ++__current_;
+ if (__st == __match_no_character_list)
+ return false;
+ break;
+ }
+
+ auto __after_pos = __current_pos_ + __equiv_size;
+ auto __transformed = __gstate.__machine_.__traits_.transform_primary(__current_, __current_ + 1);
+ for (size_t __i = 0; __i != __equiv_count; ++__i) {
+ auto __size = __read_uleb(__gstate.__machine(), __current_pos_);
+ basic_string<_CharT> __str;
+ std::transform(__gstate.__machine().begin() + __current_pos_,
+ __gstate.__machine().begin() + __current_pos_ + __size,
+ std::back_inserter(__str),
+ [](__interpreter_info<_CharT> __v) { return __v.__char_; });
+ __current_pos_ += __size;
+ if (__transformed == __str) {
+ __found = true;
+ break;
+ }
+ }
+
+ __current_pos_ = __after_pos;
+
+ if (__found) {
+ ++__current_;
+ if (__st == __match_no_character_list)
+ return false;
+ break;
+ }
+
+ if (__st == __match_no_character_list) {
+ ++__current_;
+ break;
+ }
+ return false;
+
+ } break;
+
+ case __marked_subexpression_begin: {
+ auto __match = __read_uleb(__gstate.__machine(), __current_pos_);
+ __sub_matches_[__match].first = __current_;
+ } break;
+
+ case __marked_subexpression_end: {
+ auto __match = __read_uleb(__gstate.__machine(), __current_pos_);
+ __sub_matches_[__match].second = __current_;
+ __sub_matches_[__match].matched = true;
+ } break;
+
+ default:
+ std::__libcpp_unreachable();
+ }
+ }
+ }
+ };
+
+ bool __at_first_;
+ stack<__local_execution_state> __states_;
+ const __interpreter& __machine_;
+
+ __global_execution_state(bool __at_first, __local_execution_state __initial_state, const __interpreter& __machine)
+ : __at_first_(__at_first), __machine_(__machine) {
+ __states_.push(std::move(__initial_state));
+ }
+
+ const vector<__interpreter_info<_CharT> >& __machine() { return __machine_.__machine_; }
+
+ bool __execute(const _CharT* __first, const _CharT* __last) {
+ while (!__states_.empty()) {
+ auto __st = std::move(__states_.top());
+ __states_.pop();
+ if (__st.__execute(__first, __last, *this)) {
+ __states_.push(std::move(__st));
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ void push_back(__interpreter_info<_CharT> __info) { __machine_.push_back(__info); }
+
+ template <class _Range>
+ void append_range(_Range&& __range) {
+ __machine_.insert(__machine_.end(), begin(__range), end(__range));
+ }
+
+ void insert(size_t __offset, vector<__interpreter_info<_CharT> >& __info) {
+ __machine_.insert(__machine_.begin() + __offset, __info.begin(), __info.end());
+ }
+
+ template <class _Container>
+ static void __write_uleb(_Container& __machine, size_t __val) {
+ do {
+ uint8_t __byte = __val & 0x7f;
+ __val >>= 7;
+ if (__val)
+ __byte |= 0x80;
+ __machine.push_back(__byte);
+ } while (__val);
+ }
+
+ template <class _Container>
+ void __write_string(_Container& __machine, basic_string_view<_CharT> __val) {
+ __write_uleb(__machine, __val.size());
+ __machine.insert(__machine.end(), __val.begin(), __val.end());
+ }
+
+ template <class _Container>
+ static void __push_relative_jump(_Container& __machine, size_t __offset) {
+ __machine.push_back(__state::__relative_jump);
+ __write_uleb(__machine, __offset);
+ }
+
+public:
+ __interpreter(_Traits __traits) : __traits_(__traits) {}
+
+ void __push_any_matcher() { push_back(__state::__match_any); }
+ void __push_end_state() { push_back(__state::__end_state); }
+ void __push_start_anchor() { push_back(__state::__start_anchor); }
+ void __push_end_anchor() { push_back(__state::__end_anchor); }
+
+ void __push_char_matcher(_CharT __char,
+ regex_constants::syntax_option_type __flags = regex_constants::syntax_option_type()) {
+ if (__flags & regex_constants::icase) {
+ push_back(__state::__match_icase_char);
+ push_back(__traits_.translate_nocase(__char));
+ } else {
+ push_back(__state::__match_char);
+ push_back(__char);
+ }
+ }
+
+ void __push_subexpression_begin(size_t __num) {
+ push_back(__state::__marked_subexpression_begin);
+ __write_uleb(*this, __num);
+ }
+
+ void __push_subexpression_end(size_t __num) {
+ push_back(__state::__marked_subexpression_end);
+ __write_uleb(*this, __num);
+ }
+
+ void __push_n_matcher(size_t __expr_start, size_t __count) {
+ vector<__interpreter_info<_CharT> > __buffer;
+ __buffer.push_back(__state::__match_n_times);
+ __write_uleb(__buffer, __count);
+ __write_uleb(__buffer, __machine_.size() - __expr_start + 1);
+ insert(__expr_start, __buffer);
+ push_back(__state::__end_state);
+ }
+
+ void __push_n_to_m_matcher(size_t __expr_start, size_t __min, size_t __max) {
+ vector<__interpreter_info<_CharT> > __buffer;
+ __push_relative_jump(__buffer, size() - __expr_start);
+ insert(__expr_start, __buffer);
+ __expr_start += __buffer.size();
+ push_back(__state::__branch_n_to_m_matcher);
+ __write_uleb(__machine_, __initial_loop_values_.size());
+ __write_uleb(__machine_, size() - __expr_start);
+ __initial_loop_values_.push_back(__min);
+ __initial_loop_values_.push_back(__max - __min);
+ }
+
+ void __push_backref_matcher(size_t __ref,
+ regex_constants::syntax_option_type __flags = regex_constants::syntax_option_type()) {
+ push_back((__flags & regex_constants::icase) ? __state::__match_icase_backref : __state::__match_backref);
+ __write_uleb(*this, __ref);
+ }
+
+ void __push_alternative(size_t __expr1_start, size_t __expr2_start) {
+ vector<__interpreter_info<_CharT> > __buffer;
+ __buffer.push_back(__state::__branch_alternative);
+ __write_uleb(__buffer, __expr2_start - __expr1_start);
+ insert(__expr1_start, __buffer);
+ __expr2_start += __buffer.size();
+ __buffer.clear();
+ __push_relative_jump(__buffer, size() - __expr2_start);
+ insert(__expr2_start, __buffer);
+ }
+
+ void __push_bracket_expr(bool __negate, const __bracket_expr<_CharT, _Traits>& __expr) {
+ push_back(__negate ? __state::__match_no_character_list : __state::__match_character_list);
+
+ _CharT __buffer[std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1))];
+ __builtin_memcpy(__buffer, &__expr.__mask_, sizeof(__buffer));
+ append_range(__buffer);
+
+ basic_string<_CharT> __equivalences_buffer;
+ for (auto& __eq : __expr.__equivalences_)
+ __write_string(__equivalences_buffer, __eq);
+ __write_uleb(*this, __expr.__chars_.size());
+ __write_uleb(*this, __expr.__digraphs_.size() / 2);
+ __write_uleb(*this, __expr.__ranges_.size() / 4);
+ __write_uleb(*this, __expr.__equivalences_.size());
+ __write_uleb(*this, __equivalences_buffer.size());
+ append_range(__expr.__chars_);
+ append_range(__expr.__digraphs_);
+ append_range(__expr.__ranges_);
+ append_range(__equivalences_buffer);
+ }
+
+ size_t size() const { return __machine_.size(); }
+
+ __global_execution_state
+ __get_exec_state(vector<sub_match<const _CharT*> >& __sub_matches, const _CharT* __current, bool __at_first) const {
+ typename __global_execution_state::__local_execution_state __base_state;
+ __base_state.__sub_matches_ = __sub_matches;
+ __base_state.__current_ = __current;
+ __base_state.__loop_values_ = __initial_loop_values_;
+ __base_state.__loop_starts_.resize(__initial_loop_values_.size());
+ __base_state.__current_pos_ = 0;
+ return __global_execution_state(__at_first, __base_state, *this);
+ }
+
+ _Traits __get_traits() { return __traits_; }
+};
+} // namespace __regex
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___REGEX_INTERPRETER_H
diff --git a/libcxx/include/__regex/parser_common.h b/libcxx/include/__regex/parser_common.h
new file mode 100644
index 0000000000000..a7c344dcd33bf
--- /dev/null
+++ b/libcxx/include/__regex/parser_common.h
@@ -0,0 +1,276 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___REGEX_ECMA_PARSER_H
+#define _LIBCPP___REGEX_ECMA_PARSER_H
+
+#include <__algorithm/search.h>
+#include <__config>
+#include <__regex/interpreter.h>
+#include <__regex/regex_error.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace __regex {
+
+// bracket expression parsing
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+bool __parse_character_class(
+ __interpreter<_CharT, _Traits>& __machine,
+ __bracket_expr<_CharT, _Traits>& __buffer,
+ _ForwardIterator& __first,
+ _ForwardIterator __last,
+ regex_constants::syntax_option_type __flags) {
+ char __equal_close[2] = {':', ']'};
+ auto __closing_sequence = std::search(__first, __last, __equal_close, __equal_close + 2);
+
+ if (__closing_sequence == __last)
+ std::__throw_regex_error<regex_constants::error_brack>();
+
+ auto __class_type =
+ __machine.__get_traits().lookup_classname(__first, __closing_sequence, __flags & regex_constants::icase);
+
+ if (__class_type == 0)
+ std::__throw_regex_error<regex_constants::error_ctype>();
+
+ __buffer.__mask_ |= __class_type;
+ __first = std::next(__closing_sequence, 2);
+
+ return true;
+}
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+bool __parse_equivalence_class(__interpreter<_CharT, _Traits>& __machine,
+ __bracket_expr<_CharT, _Traits>& __buffer,
+ _ForwardIterator& __first,
+ _ForwardIterator __last) {
+ char __equal_close[2] = {'=', ']'};
+ auto __closing_sequence = std::search(__first, __last, __equal_close, __equal_close + 2);
+
+ if (__closing_sequence == __last)
+ std::__throw_regex_error<regex_constants::error_brack>();
+
+ auto __collate_name = __machine.__get_traits().lookup_collatename(__first, __closing_sequence);
+ if (__collate_name.empty())
+ std::__throw_regex_error<regex_constants::error_collate>();
+
+ auto __equiv_name = __machine.__get_traits().transform_primary(__collate_name.begin(), __collate_name.end());
+ if (!__equiv_name.empty()) {
+ __buffer.__equivalences_.push_back(std::move(__equiv_name));
+ __first = std::next(__closing_sequence, 2);
+ return true;
+ }
+
+ switch (__collate_name.size()) {
+ case 1:
+ __buffer.__chars_.push_back(__collate_name[0]);
+ break;
+ case 2:
+ __buffer.__digraphs_.push_back(__collate_name[0]);
+ __buffer.__digraphs_.push_back(__collate_name[1]);
+ break;
+ default:
+ std::__throw_regex_error<regex_constants::error_collate>();
+ }
+ __first = std::next(__closing_sequence, 2);
+ return true;
+}
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+void __parse_collating_symbol(__interpreter<_CharT, _Traits>& __machine,
+ basic_string<_CharT>& __buffer,
+ _ForwardIterator& __first,
+ _ForwardIterator __last) {
+ char __equal_close[2] = {'.', ']'};
+ auto __closing_sequence = std::search(__first, __last, __equal_close, __equal_close + 2);
+
+ if (__closing_sequence == __last)
+ std::__throw_regex_error<regex_constants::error_brack>();
+
+ __buffer = __machine.__get_traits().lookup_collatename(__first, __closing_sequence);
+ switch (__buffer.size()) {
+ case 1:
+ case 2:
+ break;
+ default:
+ std::__throw_regex_error<regex_constants::error_collate>();
+ }
+
+ __first = std::next(__closing_sequence, 2);
+}
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+bool __parse_expression_term(
+ __interpreter<_CharT, _Traits>& __machine,
+ __bracket_expr<_CharT, _Traits>& __buffer,
+ _ForwardIterator& __first,
+ _ForwardIterator __last,
+ regex_constants::syntax_option_type __flags) {
+ _LIBCPP_ASSERT_INTERNAL(__first != __last, "Expected parseable character");
+
+ if (*__first == ']')
+ return false;
+ auto __next = std::next(__first);
+ if (__next == __last)
+ return false;
+
+ if (*__first == '[') {
+ if (*__next == '=') {
+ __first = ++__next;
+ return __regex::__parse_equivalence_class(__machine, __buffer, __first, __last);
+ }
+
+ if (*__next == ':') {
+ __first = ++__next;
+ return __regex::__parse_character_class(__machine, __buffer, __first, __last, __flags);
+ }
+ }
+
+ basic_string<_CharT> __start_range;
+ if (*__first == '[' && *__next == '.') {
+ __first = ++__next;
+ __regex::__parse_collating_symbol(__machine, __start_range, __first, __last);
+ } else {
+ __start_range = *__first;
+ ++__first;
+ }
+
+ if (__first == __last)
+ return false;
+
+ if (*__first == ']') {
+ if (__start_range.size() == 1) {
+ __buffer.__chars_.push_back(__start_range[0]);
+ } else {
+ _LIBCPP_ASSERT_INTERNAL(__start_range.size() == 2, "Unexpected range");
+ __buffer.__digraphs_.insert(__buffer.__digraphs_.end(), __start_range.begin(), __start_range.end());
+ }
+ return true;
+ }
+
+ __next = std::next(__first);
+ if (__next == __last)
+ return false;
+
+ if (*__first != '-' || *__next == ']') {
+ if (__start_range.size() == 1) {
+ __buffer.__chars_.push_back(__start_range[0]);
+ } else {
+ _LIBCPP_ASSERT_INTERNAL(__start_range.size() == 2, "Unexpected range");
+ __buffer.__digraphs_.insert(__buffer.__digraphs_.end(), __start_range.begin(), __start_range.end());
+ }
+ return true;
+ }
+
+ basic_string<_CharT> __end_range;
+ __first = __next;
+ ++__next;
+ if (__next == __last)
+ return false;
+ if (*__first == '[' && *__next == '.') {
+ __first = ++__next;
+ __parse_collating_symbol(__machine, __end_range, __first, __last);
+ } else {
+ __end_range = *__first;
+ ++__first;
+ }
+ __buffer.__ranges_.push_back(__start_range[0]);
+ __buffer.__ranges_.push_back(__start_range.size() == 2 ? __start_range[1] : '\0');
+ __buffer.__ranges_.push_back(__end_range[0]);
+ __buffer.__ranges_.push_back(__end_range.size() == 2 ? __end_range[1] : '\0');
+
+ return true;
+}
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+void __parse_follow_list(
+ __interpreter<_CharT, _Traits>& __machine,
+ __bracket_expr<_CharT, _Traits>& __buffer,
+ _ForwardIterator& __first,
+ _ForwardIterator __last,
+ regex_constants::syntax_option_type __flags) {
+ _LIBCPP_ASSERT_INTERNAL(__first != __last, "Expected parseable character");
+
+ while (__regex::__parse_expression_term(__machine, __buffer, __first, __last, __flags))
+ ;
+}
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+bool __parse_bracket_expression(
+ __interpreter<_CharT, _Traits>& __machine,
+ _ForwardIterator& __first,
+ _ForwardIterator __last,
+ regex_constants::syntax_option_type __flags) {
+ _LIBCPP_ASSERT_INTERNAL(__first != __last, "Expected parseable character");
+ if (*__first != '[')
+ return false;
+ ++__first;
+ if (__first == __last)
+ std::__throw_regex_error<regex_constants::error_brack>();
+ bool __negate = false;
+ if (*__first == '^') {
+ ++__first;
+ if (__first == __last)
+ std::__throw_regex_error<regex_constants::error_brack>();
+ __negate = true;
+ }
+ __bracket_expr<_CharT, _Traits> __buffer;
+
+ if (*__first == ']') {
+ __buffer.__chars_.push_back(']');
+ ++__first;
+ if (__first == __last)
+ std::__throw_regex_error<regex_constants::error_brack>();
+ }
+
+ __regex::__parse_follow_list(__machine, __buffer, __first, __last, __flags);
+ if (__first == __last)
+ std::__throw_regex_error<regex_constants::error_brack>();
+ if (*__first == '-') {
+ __buffer.__chars_.push_back('-');
+ ++__first;
+ }
+ if (__first == __last || *__first != ']')
+ std::__throw_regex_error<regex_constants::error_brack>();
+ ++__first;
+ __machine.__push_bracket_expr(__negate, __buffer);
+ return true;
+}
+
+// dup count parsing
+
+struct __dup_count_result {
+ size_t __num_;
+ bool __success_ = false;
+
+ __dup_count_result() = default;
+ __dup_count_result(size_t __num, bool __success) : __num_(__num), __success_(__success) {}
+
+ operator bool() const { return __success_; }
+};
+
+template <class _ForwardIterator>
+__dup_count_result __parse_dup_count(_ForwardIterator& __first, _ForwardIterator __last) {
+ if (__first == __last || *__first < '0' || *__first > '9')
+ return __dup_count_result();
+ size_t __num = 0;
+ for (; __first != __last && *__first >= '0' && *__first <= '9'; ++__first) {
+ if (__num >= numeric_limits<size_t>::max() / 10)
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ __num *= 10;
+ __num += *__first - '0';
+ }
+ return __dup_count_result(__num, true);
+}
+
+} // namespace __regex
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___REGEX_BASIC_PARSER_H
diff --git a/libcxx/include/__regex/regex_error.h b/libcxx/include/__regex/regex_error.h
new file mode 100644
index 0000000000000..925074ccc2485
--- /dev/null
+++ b/libcxx/include/__regex/regex_error.h
@@ -0,0 +1,176 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___REGEX_REGEX_ERROR_H
+#define _LIBCPP___REGEX_REGEX_ERROR_H
+
+#include <__config>
+#include <stdexcept>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace regex_constants {
+
+// syntax_option_type
+
+enum syntax_option_type {
+ icase = 1 << 0,
+ nosubs = 1 << 1,
+ optimize = 1 << 2,
+ collate = 1 << 3,
+#ifdef _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO
+ ECMAScript = 1 << 9,
+#else
+ ECMAScript = 0,
+#endif
+ basic = 1 << 4,
+ extended = 1 << 5,
+ awk = 1 << 6,
+ grep = 1 << 7,
+ egrep = 1 << 8,
+ // 1 << 9 may be used by ECMAScript
+ multiline = 1 << 10
+};
+
+_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR syntax_option_type __get_grammar(syntax_option_type __g) {
+#ifdef _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO
+ return static_cast<syntax_option_type>(__g & 0x3F0);
+#else
+ return static_cast<syntax_option_type>(__g & 0x1F0);
+#endif
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR syntax_option_type operator~(syntax_option_type __x) {
+ return syntax_option_type(~int(__x) & 0x1FF);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR syntax_option_type
+operator&(syntax_option_type __x, syntax_option_type __y) {
+ return syntax_option_type(int(__x) & int(__y));
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR syntax_option_type
+operator|(syntax_option_type __x, syntax_option_type __y) {
+ return syntax_option_type(int(__x) | int(__y));
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR syntax_option_type
+operator^(syntax_option_type __x, syntax_option_type __y) {
+ return syntax_option_type(int(__x) ^ int(__y));
+}
+
+inline _LIBCPP_HIDE_FROM_ABI syntax_option_type& operator&=(syntax_option_type& __x, syntax_option_type __y) {
+ __x = __x & __y;
+ return __x;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI syntax_option_type& operator|=(syntax_option_type& __x, syntax_option_type __y) {
+ __x = __x | __y;
+ return __x;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI syntax_option_type& operator^=(syntax_option_type& __x, syntax_option_type __y) {
+ __x = __x ^ __y;
+ return __x;
+}
+
+// match_flag_type
+
+enum match_flag_type {
+ match_default = 0,
+ match_not_bol = 1 << 0,
+ match_not_eol = 1 << 1,
+ match_not_bow = 1 << 2,
+ match_not_eow = 1 << 3,
+ match_any = 1 << 4,
+ match_not_null = 1 << 5,
+ match_continuous = 1 << 6,
+ match_prev_avail = 1 << 7,
+ format_default = 0,
+ format_sed = 1 << 8,
+ format_no_copy = 1 << 9,
+ format_first_only = 1 << 10,
+ __no_update_pos = 1 << 11,
+ __full_match = 1 << 12
+};
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR match_flag_type operator~(match_flag_type __x) {
+ return match_flag_type(~int(__x) & 0x0FFF);
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR match_flag_type operator&(match_flag_type __x, match_flag_type __y) {
+ return match_flag_type(int(__x) & int(__y));
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR match_flag_type operator|(match_flag_type __x, match_flag_type __y) {
+ return match_flag_type(int(__x) | int(__y));
+}
+
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR match_flag_type operator^(match_flag_type __x, match_flag_type __y) {
+ return match_flag_type(int(__x) ^ int(__y));
+}
+
+inline _LIBCPP_HIDE_FROM_ABI match_flag_type& operator&=(match_flag_type& __x, match_flag_type __y) {
+ __x = __x & __y;
+ return __x;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI match_flag_type& operator|=(match_flag_type& __x, match_flag_type __y) {
+ __x = __x | __y;
+ return __x;
+}
+
+inline _LIBCPP_HIDE_FROM_ABI match_flag_type& operator^=(match_flag_type& __x, match_flag_type __y) {
+ __x = __x ^ __y;
+ return __x;
+}
+
+enum error_type {
+ error_collate = 1,
+ error_ctype,
+ error_escape,
+ error_backref,
+ error_brack,
+ error_paren,
+ error_brace,
+ error_badbrace,
+ error_range,
+ error_space,
+ error_badrepeat,
+ error_complexity,
+ error_stack,
+ __re_err_grammar,
+ __re_err_empty,
+ __re_err_unknown,
+ __re_err_parse
+};
+
+} // namespace regex_constants
+
+class _LIBCPP_EXPORTED_FROM_ABI regex_error : public runtime_error {
+ regex_constants::error_type __code_;
+
+public:
+ explicit regex_error(regex_constants::error_type __ecode);
+ _LIBCPP_HIDE_FROM_ABI regex_error(const regex_error&) _NOEXCEPT = default;
+ ~regex_error() _NOEXCEPT override;
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI regex_constants::error_type code() const { return __code_; }
+};
+
+template <regex_constants::error_type _Ev>
+[[__noreturn__]] inline _LIBCPP_HIDE_FROM_ABI void __throw_regex_error() {
+#if _LIBCPP_HAS_EXCEPTIONS
+ throw regex_error(_Ev);
+#else
+ _LIBCPP_VERBOSE_ABORT("regex_error was thrown in -fno-exceptions mode");
+#endif
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___REGEX_REGEX_ERROR_H
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 0be8b4703c725..7cdde4ecd52a3 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -823,6 +823,8 @@ typedef regex_token_iterator<wstring::const_iterator> wsregex_token_iterator;
# include <__memory/pointer_traits.h>
# include <__memory/shared_ptr.h>
# include <__memory_resource/polymorphic_allocator.h>
+# include <__regex/basic_parser.h>
+# include <__regex/regex_error.h>
# include <__type_traits/is_swappable.h>
# include <__utility/move.h>
# include <__utility/pair.h>
@@ -846,163 +848,6 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
-namespace regex_constants {
-
-// syntax_option_type
-
-enum syntax_option_type {
- icase = 1 << 0,
- nosubs = 1 << 1,
- optimize = 1 << 2,
- collate = 1 << 3,
-# ifdef _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO
- ECMAScript = 1 << 9,
-# else
- ECMAScript = 0,
-# endif
- basic = 1 << 4,
- extended = 1 << 5,
- awk = 1 << 6,
- grep = 1 << 7,
- egrep = 1 << 8,
- // 1 << 9 may be used by ECMAScript
- multiline = 1 << 10
-};
-
-_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR syntax_option_type __get_grammar(syntax_option_type __g) {
-# ifdef _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO
- return static_cast<syntax_option_type>(__g & 0x3F0);
-# else
- return static_cast<syntax_option_type>(__g & 0x1F0);
-# endif
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR syntax_option_type operator~(syntax_option_type __x) {
- return syntax_option_type(~int(__x) & 0x1FF);
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR syntax_option_type
-operator&(syntax_option_type __x, syntax_option_type __y) {
- return syntax_option_type(int(__x) & int(__y));
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR syntax_option_type
-operator|(syntax_option_type __x, syntax_option_type __y) {
- return syntax_option_type(int(__x) | int(__y));
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR syntax_option_type
-operator^(syntax_option_type __x, syntax_option_type __y) {
- return syntax_option_type(int(__x) ^ int(__y));
-}
-
-inline _LIBCPP_HIDE_FROM_ABI syntax_option_type& operator&=(syntax_option_type& __x, syntax_option_type __y) {
- __x = __x & __y;
- return __x;
-}
-
-inline _LIBCPP_HIDE_FROM_ABI syntax_option_type& operator|=(syntax_option_type& __x, syntax_option_type __y) {
- __x = __x | __y;
- return __x;
-}
-
-inline _LIBCPP_HIDE_FROM_ABI syntax_option_type& operator^=(syntax_option_type& __x, syntax_option_type __y) {
- __x = __x ^ __y;
- return __x;
-}
-
-// match_flag_type
-
-enum match_flag_type {
- match_default = 0,
- match_not_bol = 1 << 0,
- match_not_eol = 1 << 1,
- match_not_bow = 1 << 2,
- match_not_eow = 1 << 3,
- match_any = 1 << 4,
- match_not_null = 1 << 5,
- match_continuous = 1 << 6,
- match_prev_avail = 1 << 7,
- format_default = 0,
- format_sed = 1 << 8,
- format_no_copy = 1 << 9,
- format_first_only = 1 << 10,
- __no_update_pos = 1 << 11,
- __full_match = 1 << 12
-};
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR match_flag_type operator~(match_flag_type __x) {
- return match_flag_type(~int(__x) & 0x0FFF);
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR match_flag_type operator&(match_flag_type __x, match_flag_type __y) {
- return match_flag_type(int(__x) & int(__y));
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR match_flag_type operator|(match_flag_type __x, match_flag_type __y) {
- return match_flag_type(int(__x) | int(__y));
-}
-
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR match_flag_type operator^(match_flag_type __x, match_flag_type __y) {
- return match_flag_type(int(__x) ^ int(__y));
-}
-
-inline _LIBCPP_HIDE_FROM_ABI match_flag_type& operator&=(match_flag_type& __x, match_flag_type __y) {
- __x = __x & __y;
- return __x;
-}
-
-inline _LIBCPP_HIDE_FROM_ABI match_flag_type& operator|=(match_flag_type& __x, match_flag_type __y) {
- __x = __x | __y;
- return __x;
-}
-
-inline _LIBCPP_HIDE_FROM_ABI match_flag_type& operator^=(match_flag_type& __x, match_flag_type __y) {
- __x = __x ^ __y;
- return __x;
-}
-
-enum error_type {
- error_collate = 1,
- error_ctype,
- error_escape,
- error_backref,
- error_brack,
- error_paren,
- error_brace,
- error_badbrace,
- error_range,
- error_space,
- error_badrepeat,
- error_complexity,
- error_stack,
- __re_err_grammar,
- __re_err_empty,
- __re_err_unknown,
- __re_err_parse
-};
-
-} // namespace regex_constants
-
-class _LIBCPP_EXPORTED_FROM_ABI regex_error : public runtime_error {
- regex_constants::error_type __code_;
-
-public:
- explicit regex_error(regex_constants::error_type __ecode);
- _LIBCPP_HIDE_FROM_ABI regex_error(const regex_error&) _NOEXCEPT = default;
- ~regex_error() _NOEXCEPT override;
- [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI regex_constants::error_type code() const { return __code_; }
-};
-
-template <regex_constants::error_type _Ev>
-[[__noreturn__]] inline _LIBCPP_HIDE_FROM_ABI void __throw_regex_error() {
-# if _LIBCPP_HAS_EXCEPTIONS
- throw regex_error(_Ev);
-# else
- _LIBCPP_VERBOSE_ABORT("regex_error was thrown in -fno-exceptions mode");
-# endif
-}
-
template <class _CharT>
struct regex_traits {
public:
@@ -1339,50 +1184,6 @@ inline int regex_traits<_CharT>::__regex_traits_value(wchar_t __ch, int __radix)
}
# endif
-template <class _CharT>
-class __node;
-
-template <class _BidirectionalIterator>
-class sub_match;
-
-template <class _BidirectionalIterator, class _Allocator = allocator<sub_match<_BidirectionalIterator> > >
-class match_results;
-
-template <class _CharT>
-struct __state {
- enum {
- __end_state = -1000,
- __consume_input, // -999
- __begin_marked_expr, // -998
- __end_marked_expr, // -997
- __pop_state, // -996
- __accept_and_consume, // -995
- __accept_but_not_consume, // -994
- __reject, // -993
- __split,
- __repeat
- };
-
- int __do_;
- const _CharT* __first_;
- const _CharT* __current_;
- const _CharT* __last_;
- vector<sub_match<const _CharT*> > __sub_matches_;
- vector<pair<size_t, const _CharT*> > __loop_data_;
- const __node<_CharT>* __node_;
- regex_constants::match_flag_type __flags_;
- bool __at_first_;
-
- _LIBCPP_HIDE_FROM_ABI __state()
- : __do_(0),
- __first_(nullptr),
- __current_(nullptr),
- __last_(nullptr),
- __node_(nullptr),
- __flags_(),
- __at_first_(false) {}
-};
-
// __node
template <class _CharT>
@@ -1871,6 +1672,28 @@ void __word_boundary<_CharT, _Traits>::__exec(__state& __s) const {
}
}
+template <class _CharT, class _Traits>
+class __interpreter_state : public __owns_one_state<_CharT> {
+ __regex::__interpreter<_CharT, _Traits> __machine_;
+
+public:
+ _LIBCPP_HIDE_FROM_ABI __interpreter_state(__regex::__interpreter<_CharT, _Traits> __machine, __node<_CharT>* __s)
+ : __owns_one_state<_CharT>(__s), __machine_(std::move(__machine)) {}
+
+ _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __exec(__state<_CharT>& __state) const override {
+ auto __exec_state = __machine_.__get_exec_state(__state.__sub_matches_, __state.__current_, __state.__at_first_);
+ if (!__exec_state.__execute(__state.__first_, __state.__last_)) {
+ __state.__do_ = std::__state<_CharT>::__reject;
+ __state.__node_ = nullptr;
+ return;
+ }
+ __state.__do_ = std::__state<_CharT>::__end_state;
+ auto& __matched_state = __exec_state.__states_.top();
+ __state.__current_ = __matched_state.__current_;
+ __state.__sub_matches_ = __matched_state.__sub_matches_;
+ }
+};
+
// __l_anchor
template <class _CharT>
@@ -2475,37 +2298,6 @@ private:
template <class _ForwardIterator>
_ForwardIterator __parse(_ForwardIterator __first, _ForwardIterator __last);
template <class _ForwardIterator>
- _ForwardIterator __parse_basic_reg_exp(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_RE_expression(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_simple_RE(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_nondupl_RE(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_one_char_or_coll_elem_RE(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_Back_open_paren(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_Back_close_paren(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_Back_open_brace(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_Back_close_brace(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_BACKREF(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_ORD_CHAR(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_QUOTED_CHAR(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_RE_dupl_symbol(
- _ForwardIterator __first,
- _ForwardIterator __last,
- __owns_one_state<_CharT>* __s,
- unsigned __mexp_begin,
- unsigned __mexp_end);
- template <class _ForwardIterator>
_ForwardIterator __parse_ERE_dupl_symbol(
_ForwardIterator __first,
_ForwardIterator __last,
@@ -2565,8 +2357,6 @@ private:
template <class _ForwardIterator>
_ForwardIterator __parse_pattern_character(_ForwardIterator __first, _ForwardIterator __last);
template <class _ForwardIterator>
- _ForwardIterator __parse_grep(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
_ForwardIterator __parse_egrep(_ForwardIterator __first, _ForwardIterator __last);
template <class _ForwardIterator>
_ForwardIterator __parse_class_escape(
@@ -2806,15 +2596,21 @@ _ForwardIterator basic_regex<_CharT, _Traits>::__parse(_ForwardIterator __first,
__first = __parse_ecma_exp(__first, __last);
break;
case basic:
- __first = __parse_basic_reg_exp(__first, __last);
- break;
+ case grep: {
+ __regex::__basic::__parser<_CharT, _Traits, _ForwardIterator> __parser(__first, __last, __traits_, flags());
+ if (__get_grammar(__flags_) == basic)
+ __parser.__parse_basic();
+ else
+ __parser.__parse_grep();
+ __end_->first() = new __interpreter_state<_CharT, _Traits>(__parser.__extract_interpreter(), __end_->first());
+ __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
+ __marked_count_ = __parser.mark_count();
+ return __last;
+ }
case extended:
case awk:
__first = __parse_extended_reg_exp(__first, __last);
break;
- case grep:
- __first = __parse_grep(__first, __last);
- break;
case egrep:
__first = __parse_egrep(__first, __last);
break;
@@ -2824,31 +2620,6 @@ _ForwardIterator basic_regex<_CharT, _Traits>::__parse(_ForwardIterator __first,
return __first;
}
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_basic_reg_exp(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- if (*__first == '^') {
- __push_l_anchor();
- ++__first;
- }
- if (__first != __last) {
- __first = __parse_RE_expression(__first, __last);
- if (__first != __last) {
- _ForwardIterator __temp = std::next(__first);
- if (__temp == __last && *__first == '$') {
- __push_r_anchor();
- ++__first;
- }
- }
- }
- if (__first != __last)
- std::__throw_regex_error<regex_constants::__re_err_empty>();
- }
- return __first;
-}
-
template <class _CharT, class _Traits>
template <class _ForwardIterator>
_ForwardIterator
@@ -2918,73 +2689,6 @@ basic_regex<_CharT, _Traits>::__parse_ERE_expression(_ForwardIterator __first, _
return __first;
}
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_RE_expression(_ForwardIterator __first, _ForwardIterator __last) {
- while (true) {
- _ForwardIterator __temp = __parse_simple_RE(__first, __last);
- if (__temp == __first)
- break;
- __first = __temp;
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_simple_RE(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- __owns_one_state<_CharT>* __e = __end_;
- unsigned __mexp_begin = __marked_count_;
- _ForwardIterator __temp = __parse_nondupl_RE(__first, __last);
- if (__temp != __first)
- __first = __parse_RE_dupl_symbol(__temp, __last, __e, __mexp_begin + 1, __marked_count_ + 1);
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_nondupl_RE(_ForwardIterator __first, _ForwardIterator __last) {
- _ForwardIterator __temp = __first;
- __first = __parse_one_char_or_coll_elem_RE(__first, __last);
- if (__temp == __first) {
- __temp = __parse_Back_open_paren(__first, __last);
- if (__temp != __first) {
- __push_begin_marked_subexpression();
- unsigned __temp_count = __marked_count_;
- __first = __parse_RE_expression(__temp, __last);
- __temp = __parse_Back_close_paren(__first, __last);
- if (__temp == __first)
- std::__throw_regex_error<regex_constants::error_paren>();
- __push_end_marked_subexpression(__temp_count);
- __first = __temp;
- } else
- __first = __parse_BACKREF(__first, __last);
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_one_char_or_coll_elem_RE(_ForwardIterator __first, _ForwardIterator __last) {
- _ForwardIterator __temp = __parse_ORD_CHAR(__first, __last);
- if (__temp == __first) {
- __temp = __parse_QUOTED_CHAR(__first, __last);
- if (__temp == __first) {
- if (__temp != __last && *__temp == '.') {
- __push_match_any();
- ++__temp;
- } else
- __temp = __parse_bracket_expression(__first, __last);
- }
- }
- __first = __temp;
- return __first;
-}
-
template <class _CharT, class _Traits>
template <class _ForwardIterator>
_ForwardIterator
@@ -3004,89 +2708,6 @@ basic_regex<_CharT, _Traits>::__parse_one_char_or_coll_elem_ERE(_ForwardIterator
return __first;
}
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_Back_open_paren(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last) {
- if (*__first == '\\' && *__temp == '(')
- __first = ++__temp;
- }
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_Back_close_paren(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last) {
- if (*__first == '\\' && *__temp == ')')
- __first = ++__temp;
- }
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_Back_open_brace(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last) {
- if (*__first == '\\' && *__temp == '{')
- __first = ++__temp;
- }
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_Back_close_brace(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last) {
- if (*__first == '\\' && *__temp == '}')
- __first = ++__temp;
- }
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_BACKREF(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last && *__first == '\\' && __test_back_ref(*__temp))
- __first = ++__temp;
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_ORD_CHAR(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- _ForwardIterator __temp = std::next(__first);
- if (__temp == __last && *__first == '$')
- return __first;
- // Not called inside a bracket
- if (*__first == '.' || *__first == '\\' || *__first == '[')
- return __first;
- __push_char(*__first);
- ++__first;
- }
- return __first;
-}
-
template <class _CharT, class _Traits>
template <class _ForwardIterator>
_ForwardIterator basic_regex<_CharT, _Traits>::__parse_ORD_CHAR_ERE(_ForwardIterator __first, _ForwardIterator __last) {
@@ -3119,30 +2740,6 @@ _ForwardIterator basic_regex<_CharT, _Traits>::__parse_ORD_CHAR_ERE(_ForwardIter
return __first;
}
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_QUOTED_CHAR(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last) {
- if (*__first == '\\') {
- switch (*__temp) {
- case '^':
- case '.':
- case '*':
- case '[':
- case '$':
- case '\\':
- __push_char(*__temp);
- __first = ++__temp;
- break;
- }
- }
- }
- }
- return __first;
-}
-
template <class _CharT, class _Traits>
template <class _ForwardIterator>
_ForwardIterator
@@ -3181,57 +2778,6 @@ basic_regex<_CharT, _Traits>::__parse_QUOTED_CHAR_ERE(_ForwardIterator __first,
return __first;
}
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_RE_dupl_symbol(
- _ForwardIterator __first,
- _ForwardIterator __last,
- __owns_one_state<_CharT>* __s,
- unsigned __mexp_begin,
- unsigned __mexp_end) {
- if (__first != __last) {
- if (*__first == '*') {
- __push_greedy_inf_repeat(0, __s, __mexp_begin, __mexp_end);
- ++__first;
- } else {
- _ForwardIterator __temp = __parse_Back_open_brace(__first, __last);
- if (__temp != __first) {
- int __min = 0;
- __first = __temp;
- __temp = __parse_DUP_COUNT(__first, __last, __min);
- if (__temp == __first)
- std::__throw_regex_error<regex_constants::error_badbrace>();
- __first = __temp;
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_brace>();
- if (*__first != ',') {
- __temp = __parse_Back_close_brace(__first, __last);
- if (__temp == __first)
- std::__throw_regex_error<regex_constants::error_brace>();
- __push_loop(__min, __min, __s, __mexp_begin, __mexp_end, true);
- __first = __temp;
- } else {
- ++__first; // consume ','
- int __max = -1;
- __first = __parse_DUP_COUNT(__first, __last, __max);
- __temp = __parse_Back_close_brace(__first, __last);
- if (__temp == __first)
- std::__throw_regex_error<regex_constants::error_brace>();
- if (__max == -1)
- __push_greedy_inf_repeat(__min, __s, __mexp_begin, __mexp_end);
- else {
- if (__max < __min)
- std::__throw_regex_error<regex_constants::error_badbrace>();
- __push_loop(__min, __max, __s, __mexp_begin, __mexp_end, true);
- }
- __first = __temp;
- }
- }
- }
- }
- return __first;
-}
-
template <class _CharT, class _Traits>
template <class _ForwardIterator>
_ForwardIterator basic_regex<_CharT, _Traits>::__parse_ERE_dupl_symbol(
@@ -4044,33 +3590,6 @@ basic_regex<_CharT, _Traits>::__parse_pattern_character(_ForwardIterator __first
return __first;
}
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_grep(_ForwardIterator __first, _ForwardIterator __last) {
- __owns_one_state<_CharT>* __sa = __end_;
- _ForwardIterator __t1 = std::find(__first, __last, _CharT('\n'));
- if (__t1 != __first)
- __parse_basic_reg_exp(__first, __t1);
- else
- __push_empty();
- __first = __t1;
- if (__first != __last)
- ++__first;
- while (__first != __last) {
- __t1 = std::find(__first, __last, _CharT('\n'));
- __owns_one_state<_CharT>* __sb = __end_;
- if (__t1 != __first)
- __parse_basic_reg_exp(__first, __t1);
- else
- __push_empty();
- __push_alternation(__sa, __sb);
- __first = __t1;
- if (__first != __last)
- ++__first;
- }
- return __first;
-}
-
template <class _CharT, class _Traits>
template <class _ForwardIterator>
_ForwardIterator basic_regex<_CharT, _Traits>::__parse_egrep(_ForwardIterator __first, _ForwardIterator __last) {
@@ -5384,8 +4903,8 @@ typedef regex_iterator<wstring::const_iterator> wsregex_iterator;
template <class _BidirectionalIterator, class _CharT, class _Traits>
class _LIBCPP_PREFERRED_NAME(cregex_iterator) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wcregex_iterator))
- _LIBCPP_PREFERRED_NAME(sregex_iterator)
- _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wsregex_iterator)) regex_iterator {
+ _LIBCPP_PREFERRED_NAME(sregex_iterator) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wsregex_iterator))
+ regex_iterator {
public:
typedef basic_regex<_CharT, _Traits> regex_type;
typedef match_results<_BidirectionalIterator> value_type;
diff --git a/libcxx/test/std/re/re.alg/re.alg.search/basic.pass.cpp b/libcxx/test/std/re/re.alg/re.alg.search/basic.pass.cpp
index 74b4d6341e9de..80918d2b2958a 100644
--- a/libcxx/test/std/re/re.alg/re.alg.search/basic.pass.cpp
+++ b/libcxx/test/std/re/re.alg/re.alg.search/basic.pass.cpp
@@ -29,6 +29,18 @@ int main(int, char**)
assert(m.size() == 0);
assert(m.empty());
}
+ {
+ std::cmatch m;
+ assert(!std::regex_search("a", m, std::regex("\\0", std::regex_constants::basic)));
+ assert(m.size() == 0);
+ assert(m.empty());
+ }
+ {
+ std::cmatch m;
+ assert(!std::regex_search("a", m, std::regex("[a-[.hyphen.]]", std::regex_constants::basic)));
+ assert(m.size() == 0);
+ assert(m.empty());
+ }
{
std::cmatch m;
const char s[] = "a";
diff --git a/libcxx/test/std/re/re.grammar/excessive_brace_count.pass.cpp b/libcxx/test/std/re/re.grammar/excessive_brace_count.pass.cpp
index 6ed2645be89b5..0435ca29c94b0 100644
--- a/libcxx/test/std/re/re.grammar/excessive_brace_count.pass.cpp
+++ b/libcxx/test/std/re/re.grammar/excessive_brace_count.pass.cpp
@@ -20,7 +20,8 @@ int main(int, char**) {
for (std::regex_constants::syntax_option_type op :
{std::regex::basic, std::regex::grep}) {
try {
- TEST_IGNORE_NODISCARD std::regex("a\\{100000000000000000\\}", op);
+ auto regex = "a\\{" + std::to_string(std::numeric_limits<size_t>::max()) + "1\\}";
+ TEST_IGNORE_NODISCARD std::regex(regex, op);
assert(false);
} catch (const std::regex_error &e) {
assert(e.code() == std::regex_constants::error_badbrace);
>From 7bbeb0e2e53afaa53fbac8d79e8e16a831502bbc Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 5 Mar 2026 12:05:32 +0100
Subject: [PATCH 03/21] [libc++] Regex extended syntax
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__regex/basic_parser.h | 11 +-
libcxx/include/__regex/extended_parser.h | 287 ++++++++++++++++++
libcxx/include/__regex/interpreter.h | 87 ++++--
libcxx/include/__regex/parser_common.h | 60 ++++
libcxx/include/__regex/regex_error.h | 2 +
libcxx/include/regex | 223 +-------------
.../re.grammar/excessive_brace_count.pass.cpp | 3 +-
8 files changed, 433 insertions(+), 241 deletions(-)
create mode 100644 libcxx/include/__regex/extended_parser.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 1178b29eaedbe..24a4bb24d3c6f 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -795,6 +795,7 @@ set(files
__ranges/zip_transform_view.h
__ranges/zip_view.h
__regex/basic_parser.h
+ __regex/extended_parser.h
__regex/interpreter.h
__regex/parser_common.h
__regex/regex_error.h
diff --git a/libcxx/include/__regex/basic_parser.h b/libcxx/include/__regex/basic_parser.h
index d32b957557fc6..f744df1e40274 100644
--- a/libcxx/include/__regex/basic_parser.h
+++ b/libcxx/include/__regex/basic_parser.h
@@ -121,11 +121,13 @@ class __parser {
if (__parse_escaped_character('(')) {
size_t __subexpr_num = __marked_count_++;
- __machine_.__push_subexpression_begin(__subexpr_num);
+ if (!(__flags_ & regex_constants::nosubs))
+ __machine_.__push_subexpression_begin(__subexpr_num);
__parse_re_expression();
if (!__parse_escaped_character(')'))
std::__throw_regex_error<regex_constants::error_paren>();
- __machine_.__push_subexpression_end(__subexpr_num);
+ if (!(__flags_ & regex_constants::nosubs))
+ __machine_.__push_subexpression_end(__subexpr_num);
return true;
} else {
return __parse_backref();
@@ -220,7 +222,7 @@ class __parser {
public:
__parser(
_ForwardIterator __first, _ForwardIterator __last, _Traits __traits, regex_constants::syntax_option_type __flags)
- : __machine_(__traits), __first_(__first), __last_(__last), __flags_(__flags) {}
+ : __machine_(__traits, true), __first_(__first), __last_(__last), __flags_(__flags) {}
void __parse_basic() {
__parse_basic_expr();
@@ -241,11 +243,12 @@ class __parser {
while (__first_ != __last_) {
__newline = std::find(__first_, __last_, '\n');
std::swap(__last_, __newline);
+ auto __expr2_start = __machine_.size();
__parse_basic_expr();
std::swap(__last_, __newline);
if (__first_ != __newline)
std::__throw_regex_error<regex_constants::__re_err_grammar>();
- __machine_.__push_alternative(0, __machine_.size());
+ __machine_.__push_alternative(0, __expr2_start);
if (__first_ != __last_)
++__first_;
}
diff --git a/libcxx/include/__regex/extended_parser.h b/libcxx/include/__regex/extended_parser.h
new file mode 100644
index 0000000000000..92906880eec44
--- /dev/null
+++ b/libcxx/include/__regex/extended_parser.h
@@ -0,0 +1,287 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___REGEX_EXTENDED_PARSER_H
+#define _LIBCPP___REGEX_EXTENDED_PARSER_H
+
+#include <__algorithm/search.h>
+#include <__config>
+#include <__iterator/next.h>
+#include <__regex/interpreter.h>
+#include <__regex/parser_common.h>
+#include <__regex/regex_error.h>
+#include <__utility/exchange.h>
+#include <string>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace __regex::__extended {
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+class __parser {
+ __interpreter<_CharT, _Traits> __machine_;
+ _ForwardIterator __first_;
+ _ForwardIterator __last_;
+ regex_constants::syntax_option_type __flags_ = {};
+ uint8_t __marked_count_ = 0;
+ size_t __open_count_ = 0;
+
+ bool __parse_ord_char() {
+ _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "Expected valid character");
+ switch (*__first_) {
+ case '^':
+ case '.':
+ case '[':
+ case '$':
+ case '(':
+ case '|':
+ case '*':
+ case '+':
+ case '?':
+ case '{':
+ case '\\':
+ return false;
+ case ')':
+ if (__open_count_ != 0)
+ return false;
+ [[__fallthrough__]];
+ default:
+ __machine_.__push_char_matcher(*__first_, __flags_);
+ ++__first_;
+ return true;
+ }
+ }
+ bool __parse_quoted_char() {
+ _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "Expected valid character");
+ auto __next = std::next(__first_);
+ if (__next == __last_ || *__first_ != '\\')
+ return false;
+ switch (*__next) {
+ case '^':
+ case '.':
+ case '*':
+ case '[':
+ case '$':
+ case '\\':
+ case '(':
+ case ')':
+ case '|':
+ case '+':
+ case '?':
+ case '{':
+ case '}':
+ __machine_.__push_char_matcher(*__next, __flags_);
+ __first_ = ++__next;
+ return true;
+ default:
+ if (regex_constants::__get_grammar(__flags_) == regex_constants::awk) {
+ __first_ = __next;
+ __machine_.__push_char_matcher(__parse_awk_escape<_CharT>(__first_, __last_));
+ return true;
+ }
+ auto __val = __machine_.__get_traits().value(*__next, 10);
+ if (__val < 1 || __val > 9)
+ return false;
+ if (__val > __marked_count_)
+ std::__throw_regex_error<regex_constants::error_backref>();
+ __machine_.__push_backref_matcher(__val);
+ __first_ = ++__next;
+ return true;
+ }
+ }
+
+ bool __parse_one_char_or_coll_elem() {
+ if (__first_ == __last_)
+ return false;
+ if (__parse_ord_char() || __parse_quoted_char())
+ return true;
+ if (*__first_ == '.') {
+ __machine_.__push_any_matcher();
+ ++__first_;
+ return true;
+ }
+ return __regex::__parse_bracket_expression(__machine_, __first_, __last_, __flags_);
+ }
+
+ bool __parse_dupl_symbol(size_t __expr_start) {
+ if (__first_ == __last_)
+ return false;
+ switch (*__first_) {
+ case '*': {
+ ++__first_;
+ __machine_.__push_n_to_m_matcher(__expr_start, 0, numeric_limits<size_t>::max());
+ } break;
+
+ case '+': {
+ ++__first_;
+ __machine_.__push_n_to_m_matcher(__expr_start, 1, numeric_limits<size_t>::max());
+ } break;
+
+ case '?': {
+ ++__first_;
+ __machine_.__push_n_to_m_matcher(__expr_start, 0, 1);
+ } break;
+
+ case '{': {
+ ++__first_;
+ size_t __min;
+ if (auto __res = __regex::__parse_dup_count(__first_, __last_)) {
+ __min = __res.__num_;
+ } else {
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ }
+ if (__first_ == __last_)
+ std::__throw_regex_error<regex_constants::error_brace>();
+
+ switch (*__first_) {
+ case '}': {
+ ++__first_;
+ __machine_.__push_n_matcher(__expr_start, __min);
+ return true;
+ } break;
+
+ case ',': {
+ ++__first_;
+ if (__first_ == __last_)
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ if (*__first_ == '}') {
+ ++__first_;
+ __machine_.__push_n_to_m_matcher(__expr_start, __min, numeric_limits<size_t>::max());
+ return true;
+ }
+
+ size_t __max;
+ if (auto __res = __regex::__parse_dup_count(__first_, __last_)) {
+ __max = __res.__num_;
+ } else {
+ std::__throw_regex_error<regex_constants::error_brace>();
+ }
+ if (__first_ == __last_ || *__first_ != '}')
+ std::__throw_regex_error<regex_constants::error_brace>();
+ ++__first_;
+ if (__max < __min)
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ __machine_.__push_n_to_m_matcher(__expr_start, __min, __max);
+ return true;
+ } break;
+ default:
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ }
+ } break;
+ }
+ return false;
+ }
+
+ bool __parse_expression() {
+ if (__first_ == __last_)
+ return false;
+ size_t __expr_start = __machine_.size();
+ if (!__parse_one_char_or_coll_elem()) {
+ switch (*__first_) {
+ case '^':
+ ++__first_;
+ __machine_.__push_start_anchor();
+ break;
+ case '$':
+ ++__first_;
+ __machine_.__push_end_anchor();
+ break;
+ case '(': {
+ ++__first_;
+ size_t __subexpr_num = __marked_count_;
+ __marked_count_ += !(__flags_ & regex_constants::nosubs);
+ ++__open_count_;
+ if (!(__flags_ & regex_constants::nosubs))
+ __machine_.__push_subexpression_begin(__subexpr_num);
+ __parse_reg_exp(__machine_.size());
+ if (__first_ == __last_ || *__first_ != ')')
+ std::__throw_regex_error<regex_constants::error_paren>();
+ ++__first_;
+ --__open_count_;
+ if (!(__flags_ & regex_constants::nosubs))
+ __machine_.__push_subexpression_end(__subexpr_num);
+ } break;
+ default:
+ return false;
+ }
+ }
+ __parse_dupl_symbol(__expr_start);
+ return true;
+ }
+
+ bool __parse_branch() {
+ if (!__parse_expression())
+ std::__throw_regex_error<regex_constants::__re_err_empty>();
+ while (__parse_expression())
+ ;
+ return true;
+ }
+
+ void __parse_reg_exp(size_t __expr_start) {
+ if (!__parse_branch())
+ std::__throw_regex_error<regex_constants::__re_err_empty>();
+
+ while (__first_ != __last_ && *__first_ == '|') {
+ ++__first_;
+ auto __expr2_start = __machine_.size();
+ if (!__parse_branch())
+ std::__throw_regex_error<regex_constants::__re_err_empty>();
+ __machine_.__push_alternative(__expr_start, __expr2_start);
+ }
+ }
+
+public:
+ __parser(
+ _ForwardIterator __first, _ForwardIterator __last, _Traits __traits, regex_constants::syntax_option_type __flags)
+ : __machine_(__traits, true), __first_(__first), __last_(__last), __flags_(__flags) {}
+
+ void __parse_extended() {
+ __parse_reg_exp(0);
+ if (__first_ != __last_)
+ std::__throw_regex_error<regex_constants::__re_err_parse>();
+ __machine_.__push_end_state();
+ }
+
+ void __parse_egrep() {
+ auto __newline = std::find(__first_, __last_, '\n');
+ if (__newline != __first_) {
+ std::swap(__last_, __newline);
+ __parse_extended();
+ std::swap(__last_, __newline);
+ if (__first_ != __newline)
+ std::__throw_regex_error<regex_constants::__re_err_grammar>();
+ }
+ if (__first_ != __last_)
+ ++__first_;
+ while (__first_ != __last_) {
+ __newline = std::find(__first_, __last_, '\n');
+ auto __expr2_start = __machine_.size();
+ if (__newline != __first_) {
+ std::swap(__last_, __newline);
+ __parse_extended();
+ std::swap(__last_, __newline);
+ if (__first_ != __newline)
+ std::__throw_regex_error<regex_constants::__re_err_grammar>();
+ } else {
+ __machine_.__push_end_state();
+ }
+ __machine_.__push_alternative(0, __expr2_start);
+ if (__first_ != __last_)
+ ++__first_;
+ }
+ __machine_.__push_end_state();
+ }
+
+ __interpreter<_CharT, _Traits> __extract_interpreter() { return std::move(__machine_); }
+ size_t mark_count() const { return __marked_count_; }
+};
+} // namespace __regex::__extended
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___REGEX_EXTENDED_PARSER_H
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 515ce2cca3e08..4bcff9d7c7f79 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -122,6 +122,7 @@ class __interpreter {
vector<__interpreter_info<_CharT> > __machine_;
vector<size_t> __initial_loop_values_;
_Traits __traits_;
+ bool __find_longest_;
static size_t __read_uleb(const vector<__interpreter_info<_CharT> >& __machine, size_t& __current_pos) {
size_t __result = 0;
@@ -137,6 +138,14 @@ class __interpreter {
}
struct __global_execution_state {
+ struct __local_execution_state;
+
+ bool __at_first_;
+ stack<__local_execution_state> __states_;
+ const __interpreter& __machine_;
+ regex_constants::match_flag_type __flags_;
+ size_t __counter_ = 0;
+
struct __local_execution_state {
const _CharT* __current_;
vector<sub_match<const _CharT*> > __sub_matches_;
@@ -146,6 +155,7 @@ class __interpreter {
bool __execute(const _CharT* __first, const _CharT* __last, __global_execution_state& __gstate) {
while (true) {
+ ++__gstate.__counter_;
auto __st = __gstate.__machine()[__current_pos_++].__state_;
switch (__st) {
using enum __state;
@@ -161,7 +171,7 @@ class __interpreter {
} break;
case __end_state: {
- return true;
+ return !(__gstate.__flags_ & regex_constants::match_flag_type::__full_match) || __current_ == __last;
}
case __match_any: {
@@ -185,9 +195,8 @@ class __interpreter {
case __branch_alternative: {
auto __offset = __read_uleb(__gstate.__machine(), __current_pos_);
- auto __cpy = *this;
- __cpy.__current_pos_ += __offset;
- __gstate.__states_.push(std::move(__cpy));
+ __gstate.__states_.push(*this);
+ __current_pos_ += __offset;
break;
}
@@ -387,27 +396,43 @@ class __interpreter {
}
};
- bool __at_first_;
- stack<__local_execution_state> __states_;
- const __interpreter& __machine_;
-
- __global_execution_state(bool __at_first, __local_execution_state __initial_state, const __interpreter& __machine)
- : __at_first_(__at_first), __machine_(__machine) {
- __states_.push(std::move(__initial_state));
- }
-
- const vector<__interpreter_info<_CharT> >& __machine() { return __machine_.__machine_; }
+ const vector<__interpreter_info<_CharT>>& __machine() { return __machine_.__machine_; }
bool __execute(const _CharT* __first, const _CharT* __last) {
- while (!__states_.empty()) {
- auto __st = std::move(__states_.top());
- __states_.pop();
- if (__st.__execute(__first, __last, *this)) {
- __states_.push(std::move(__st));
- return true;
+ size_t __length = __last - __first + 1;
+ if (__machine_.__find_longest_) {
+ __local_execution_state __best_state;
+ bool __found_match = false;
+ while (!__states_.empty()) {
+ if (__counter_ / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ std::__throw_regex_error<regex_constants::error_complexity>();
+ auto __state = std::move(__states_.top());
+ __states_.pop();
+ if (__state.__execute(__first, __last, *this)) {
+ if (!__found_match || __best_state.__current_ < __state.__current_)
+ __best_state = std::move(__state);
+ if (__best_state.__current_ == __last) {
+ __states_.push(std::move(__best_state));
+ return true;
+ }
+ __found_match = true;
+ }
+ }
+ __states_.push(std::move(__best_state));
+ return __found_match;
+ } else {
+ while (!__states_.empty()) {
+ if (__counter_ / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ std::__throw_regex_error<regex_constants::error_complexity>();
+ auto __state = std::move(__states_.top());
+ __states_.pop();
+ if (__state.__execute(__first, __last, *this)) {
+ __states_.push(std::move(__state));
+ return true;
+ }
}
+ return false;
}
- return false;
}
};
@@ -446,7 +471,7 @@ class __interpreter {
}
public:
- __interpreter(_Traits __traits) : __traits_(__traits) {}
+ __interpreter(_Traits __traits, bool __find_longest) : __traits_(__traits), __find_longest_(__find_longest) {}
void __push_any_matcher() { push_back(__state::__match_any); }
void __push_end_state() { push_back(__state::__end_state); }
@@ -503,13 +528,14 @@ class __interpreter {
void __push_alternative(size_t __expr1_start, size_t __expr2_start) {
vector<__interpreter_info<_CharT> > __buffer;
+ __push_relative_jump(__buffer, size() - __expr2_start);
+ insert(__expr2_start, __buffer);
+ __expr2_start += __buffer.size();
+ __buffer.clear();
__buffer.push_back(__state::__branch_alternative);
__write_uleb(__buffer, __expr2_start - __expr1_start);
insert(__expr1_start, __buffer);
__expr2_start += __buffer.size();
- __buffer.clear();
- __push_relative_jump(__buffer, size() - __expr2_start);
- insert(__expr2_start, __buffer);
}
void __push_bracket_expr(bool __negate, const __bracket_expr<_CharT, _Traits>& __expr) {
@@ -535,15 +561,20 @@ class __interpreter {
size_t size() const { return __machine_.size(); }
- __global_execution_state
- __get_exec_state(vector<sub_match<const _CharT*> >& __sub_matches, const _CharT* __current, bool __at_first) const {
+ __global_execution_state __get_exec_state(
+ vector<sub_match<const _CharT*>>& __sub_matches,
+ const _CharT* __current,
+ bool __at_first,
+ regex_constants::match_flag_type __flags) const {
typename __global_execution_state::__local_execution_state __base_state;
__base_state.__sub_matches_ = __sub_matches;
__base_state.__current_ = __current;
__base_state.__loop_values_ = __initial_loop_values_;
__base_state.__loop_starts_.resize(__initial_loop_values_.size());
__base_state.__current_pos_ = 0;
- return __global_execution_state(__at_first, __base_state, *this);
+ stack<typename __global_execution_state::__local_execution_state> __s;
+ __s.push(__base_state);
+ return __global_execution_state{__at_first, __s, *this, __flags};
}
_Traits __get_traits() { return __traits_; }
diff --git a/libcxx/include/__regex/parser_common.h b/libcxx/include/__regex/parser_common.h
index a7c344dcd33bf..44b5ebd563f05 100644
--- a/libcxx/include/__regex/parser_common.h
+++ b/libcxx/include/__regex/parser_common.h
@@ -18,6 +18,56 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace __regex {
+template <class _CharT, class _ForwardIterator>
+_CharT __parse_awk_escape(_ForwardIterator& __first, _ForwardIterator __last) {
+ switch (*__first) {
+ case '\\':
+ case '"':
+ case '/':
+ return *__first++;
+
+ case 'a':
+ ++__first;
+ return '\a';
+
+ case 'b':
+ ++__first;
+ return '\b';
+
+ case 'f':
+ ++__first;
+ return '\f';
+
+ case 'n':
+ ++__first;
+ return '\n';
+
+ case 'r':
+ ++__first;
+ return '\r';
+
+ case 't':
+ ++__first;
+ return '\t';
+
+ case 'v':
+ ++__first;
+ return '\v';
+ }
+
+ auto __is_base_8_char = [](_CharT __c) { return __c >= '0' && __c <= '7'; };
+
+ if (!__is_base_8_char(*__first))
+ std::__throw_regex_error<regex_constants::error_escape>();
+ unsigned __val = *__first - '0';
+ if (++__first != __last && __is_base_8_char(*__first)) {
+ __val = 8 * __val + *__first - '0';
+ if (++__first != __last && __is_base_8_char(*__first))
+ __val = 8 * __val + *__first++ - '0';
+ }
+ return _CharT(__val);
+}
+
// bracket expression parsing
template <class _CharT, class _Traits, class _ForwardIterator>
@@ -136,6 +186,11 @@ bool __parse_expression_term(
if (*__first == '[' && *__next == '.') {
__first = ++__next;
__regex::__parse_collating_symbol(__machine, __start_range, __first, __last);
+ } else if (auto __grammar = regex_constants::__get_grammar(__flags);
+ __grammar == regex_constants::awk && *__first == '\\') {
+ if (++__first == __last)
+ return false;
+ __start_range = __parse_awk_escape<_CharT>(__first, __last);
} else {
__start_range = *__first;
++__first;
@@ -176,6 +231,11 @@ bool __parse_expression_term(
if (*__first == '[' && *__next == '.') {
__first = ++__next;
__parse_collating_symbol(__machine, __end_range, __first, __last);
+ } else if (auto __grammar = regex_constants::__get_grammar(__flags);
+ __grammar == regex_constants::awk && *__first == '\\') {
+ if (++__first == __last)
+ return false;
+ __start_range = __parse_awk_escape<_CharT>(__first, __last);
} else {
__end_range = *__first;
++__first;
diff --git a/libcxx/include/__regex/regex_error.h b/libcxx/include/__regex/regex_error.h
index 925074ccc2485..ee7811cd8edbd 100644
--- a/libcxx/include/__regex/regex_error.h
+++ b/libcxx/include/__regex/regex_error.h
@@ -14,6 +14,8 @@
_LIBCPP_BEGIN_NAMESPACE_STD
+#define _LIBCPP_REGEX_COMPLEXITY_FACTOR 4096
+
namespace regex_constants {
// syntax_option_type
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 7cdde4ecd52a3..7f3449bd92500 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -824,6 +824,7 @@ typedef regex_token_iterator<wstring::const_iterator> wsregex_token_iterator;
# include <__memory/shared_ptr.h>
# include <__memory_resource/polymorphic_allocator.h>
# include <__regex/basic_parser.h>
+# include <__regex/extended_parser.h>
# include <__regex/regex_error.h>
# include <__type_traits/is_swappable.h>
# include <__utility/move.h>
@@ -843,8 +844,6 @@ typedef regex_token_iterator<wstring::const_iterator> wsregex_token_iterator;
_LIBCPP_PUSH_MACROS
# include <__undef_macros>
-# define _LIBCPP_REGEX_COMPLEXITY_FACTOR 4096
-
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
@@ -1681,7 +1680,8 @@ public:
: __owns_one_state<_CharT>(__s), __machine_(std::move(__machine)) {}
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __exec(__state<_CharT>& __state) const override {
- auto __exec_state = __machine_.__get_exec_state(__state.__sub_matches_, __state.__current_, __state.__at_first_);
+ auto __exec_state =
+ __machine_.__get_exec_state(__state.__sub_matches_, __state.__current_, __state.__at_first_, __state.__flags_);
if (!__exec_state.__execute(__state.__first_, __state.__last_)) {
__state.__do_ = std::__state<_CharT>::__reject;
__state.__node_ = nullptr;
@@ -2324,18 +2324,6 @@ private:
template <class _ForwardIterator>
_ForwardIterator __parse_DUP_COUNT(_ForwardIterator __first, _ForwardIterator __last, int& __c);
template <class _ForwardIterator>
- _ForwardIterator __parse_extended_reg_exp(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_ERE_branch(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_ERE_expression(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_one_char_or_coll_elem_ERE(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_ORD_CHAR_ERE(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_QUOTED_CHAR_ERE(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
_ForwardIterator __parse_ecma_exp(_ForwardIterator __first, _ForwardIterator __last);
template <class _ForwardIterator>
_ForwardIterator __parse_alternative(_ForwardIterator __first, _ForwardIterator __last);
@@ -2357,8 +2345,6 @@ private:
template <class _ForwardIterator>
_ForwardIterator __parse_pattern_character(_ForwardIterator __first, _ForwardIterator __last);
template <class _ForwardIterator>
- _ForwardIterator __parse_egrep(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
_ForwardIterator __parse_class_escape(
_ForwardIterator __first,
_ForwardIterator __last,
@@ -2607,177 +2593,25 @@ _ForwardIterator basic_regex<_CharT, _Traits>::__parse(_ForwardIterator __first,
__marked_count_ = __parser.mark_count();
return __last;
}
- case extended:
case awk:
- __first = __parse_extended_reg_exp(__first, __last);
- break;
- case egrep:
- __first = __parse_egrep(__first, __last);
- break;
+ case extended:
+ case egrep: {
+ __regex::__extended::__parser<_CharT, _Traits, _ForwardIterator> __parser(__first, __last, __traits_, flags());
+ if (auto __grammar = __get_grammar(__flags_); __grammar == extended || __grammar == awk)
+ __parser.__parse_extended();
+ else
+ __parser.__parse_egrep();
+ __end_->first() = new __interpreter_state<_CharT, _Traits>(__parser.__extract_interpreter(), __end_->first());
+ __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
+ __marked_count_ = __parser.mark_count();
+ return __last;
+ }
default:
std::__throw_regex_error<regex_constants::__re_err_grammar>();
}
return __first;
}
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_extended_reg_exp(_ForwardIterator __first, _ForwardIterator __last) {
- __owns_one_state<_CharT>* __sa = __end_;
- _ForwardIterator __temp = __parse_ERE_branch(__first, __last);
- if (__temp == __first)
- std::__throw_regex_error<regex_constants::__re_err_empty>();
- __first = __temp;
- while (__first != __last && *__first == '|') {
- __owns_one_state<_CharT>* __sb = __end_;
- __temp = __parse_ERE_branch(++__first, __last);
- if (__temp == __first)
- std::__throw_regex_error<regex_constants::__re_err_empty>();
- __push_alternation(__sa, __sb);
- __first = __temp;
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_ERE_branch(_ForwardIterator __first, _ForwardIterator __last) {
- _ForwardIterator __temp = __parse_ERE_expression(__first, __last);
- if (__temp == __first)
- std::__throw_regex_error<regex_constants::__re_err_empty>();
- do {
- __first = __temp;
- __temp = __parse_ERE_expression(__first, __last);
- } while (__temp != __first);
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_ERE_expression(_ForwardIterator __first, _ForwardIterator __last) {
- __owns_one_state<_CharT>* __e = __end_;
- unsigned __mexp_begin = __marked_count_;
- _ForwardIterator __temp = __parse_one_char_or_coll_elem_ERE(__first, __last);
- if (__temp == __first && __temp != __last) {
- switch (*__temp) {
- case '^':
- __push_l_anchor();
- ++__temp;
- break;
- case '$':
- __push_r_anchor();
- ++__temp;
- break;
- case '(':
- __push_begin_marked_subexpression();
- unsigned __temp_count = __marked_count_;
- ++__open_count_;
- __temp = __parse_extended_reg_exp(++__temp, __last);
- if (__temp == __last || *__temp != ')')
- std::__throw_regex_error<regex_constants::error_paren>();
- __push_end_marked_subexpression(__temp_count);
- --__open_count_;
- ++__temp;
- break;
- }
- }
- if (__temp != __first)
- __temp = __parse_ERE_dupl_symbol(__temp, __last, __e, __mexp_begin + 1, __marked_count_ + 1);
- __first = __temp;
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_one_char_or_coll_elem_ERE(_ForwardIterator __first, _ForwardIterator __last) {
- _ForwardIterator __temp = __parse_ORD_CHAR_ERE(__first, __last);
- if (__temp == __first) {
- __temp = __parse_QUOTED_CHAR_ERE(__first, __last);
- if (__temp == __first) {
- if (__temp != __last && *__temp == '.') {
- __push_match_any();
- ++__temp;
- } else
- __temp = __parse_bracket_expression(__first, __last);
- }
- }
- __first = __temp;
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_ORD_CHAR_ERE(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- switch (*__first) {
- case '^':
- case '.':
- case '[':
- case '$':
- case '(':
- case '|':
- case '*':
- case '+':
- case '?':
- case '{':
- case '\\':
- break;
- case ')':
- if (__open_count_ == 0) {
- __push_char(*__first);
- ++__first;
- }
- break;
- default:
- __push_char(*__first);
- ++__first;
- break;
- }
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_QUOTED_CHAR_ERE(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last) {
- if (*__first == '\\') {
- switch (*__temp) {
- case '^':
- case '.':
- case '*':
- case '[':
- case '$':
- case '\\':
- case '(':
- case ')':
- case '|':
- case '+':
- case '?':
- case '{':
- case '}':
- __push_char(*__temp);
- __first = ++__temp;
- break;
- default:
- if (__get_grammar(__flags_) == awk)
- __first = __parse_awk_escape(++__first, __last);
- else if (__test_back_ref(*__temp))
- __first = ++__temp;
- break;
- }
- }
- }
- }
- return __first;
-}
-
template <class _CharT, class _Traits>
template <class _ForwardIterator>
_ForwardIterator basic_regex<_CharT, _Traits>::__parse_ERE_dupl_symbol(
@@ -3590,33 +3424,6 @@ basic_regex<_CharT, _Traits>::__parse_pattern_character(_ForwardIterator __first
return __first;
}
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_egrep(_ForwardIterator __first, _ForwardIterator __last) {
- __owns_one_state<_CharT>* __sa = __end_;
- _ForwardIterator __t1 = std::find(__first, __last, _CharT('\n'));
- if (__t1 != __first)
- __parse_extended_reg_exp(__first, __t1);
- else
- __push_empty();
- __first = __t1;
- if (__first != __last)
- ++__first;
- while (__first != __last) {
- __t1 = std::find(__first, __last, _CharT('\n'));
- __owns_one_state<_CharT>* __sb = __end_;
- if (__t1 != __first)
- __parse_extended_reg_exp(__first, __t1);
- else
- __push_empty();
- __push_alternation(__sa, __sb);
- __first = __t1;
- if (__first != __last)
- ++__first;
- }
- return __first;
-}
-
template <class _CharT, class _Traits>
bool basic_regex<_CharT, _Traits>::__test_back_ref(_CharT __c) {
unsigned __val = __traits_.value(__c, 10);
diff --git a/libcxx/test/std/re/re.grammar/excessive_brace_count.pass.cpp b/libcxx/test/std/re/re.grammar/excessive_brace_count.pass.cpp
index 0435ca29c94b0..473428e0930db 100644
--- a/libcxx/test/std/re/re.grammar/excessive_brace_count.pass.cpp
+++ b/libcxx/test/std/re/re.grammar/excessive_brace_count.pass.cpp
@@ -31,7 +31,8 @@ int main(int, char**) {
{std::regex::ECMAScript, std::regex::extended, std::regex::egrep,
std::regex::awk}) {
try {
- TEST_IGNORE_NODISCARD std::regex("a{100000000000000000}", op);
+ auto regex = "a{" + std::to_string(std::numeric_limits<size_t>::max()) + "1}";
+ TEST_IGNORE_NODISCARD std::regex(regex, op);
assert(false);
} catch (const std::regex_error &e) {
assert(e.code() == std::regex_constants::error_badbrace);
>From 885f6d60edd0d6f05cc26286684e1f641c68cb05 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 24 Mar 2026 15:11:58 +0100
Subject: [PATCH 04/21] [libc++] ECMAScript parser
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__regex/basic_parser.h | 8 +-
libcxx/include/__regex/ecma_parser.h | 446 +--
libcxx/include/__regex/extended_parser.h | 71 +-
libcxx/include/__regex/interpreter.h | 707 +++--
libcxx/include/__regex/parser_common.h | 223 +-
libcxx/include/__regex/regex_error.h | 3 +-
libcxx/include/regex | 2550 +++--------------
libcxx/src/regex.cpp | 14 +-
.../re/re.alg/re.alg.search/basic.pass.cpp | 2 +-
10 files changed, 1310 insertions(+), 2715 deletions(-)
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 24a4bb24d3c6f..70e7ee1aa503b 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -795,6 +795,7 @@ set(files
__ranges/zip_transform_view.h
__ranges/zip_view.h
__regex/basic_parser.h
+ __regex/ecma_parser.h
__regex/extended_parser.h
__regex/interpreter.h
__regex/parser_common.h
diff --git a/libcxx/include/__regex/basic_parser.h b/libcxx/include/__regex/basic_parser.h
index f744df1e40274..9b8caeb688f4a 100644
--- a/libcxx/include/__regex/basic_parser.h
+++ b/libcxx/include/__regex/basic_parser.h
@@ -173,7 +173,7 @@ class __parser {
if (!__parse_escaped_character('}'))
std::__throw_regex_error<regex_constants::error_brace>();
- __machine_.__push_n_matcher(__expr_start, __min);
+ __machine_.__push_n_to_m_matcher(__expr_start, __min, __min);
return true;
}
@@ -220,8 +220,10 @@ class __parser {
}
public:
- __parser(
- _ForwardIterator __first, _ForwardIterator __last, _Traits __traits, regex_constants::syntax_option_type __flags)
+ __parser(_ForwardIterator __first,
+ _ForwardIterator __last,
+ const _Traits& __traits,
+ regex_constants::syntax_option_type __flags)
: __machine_(__traits, true), __first_(__first), __last_(__last), __flags_(__flags) {}
void __parse_basic() {
diff --git a/libcxx/include/__regex/ecma_parser.h b/libcxx/include/__regex/ecma_parser.h
index 06fcf75db68ca..6499349410a0e 100644
--- a/libcxx/include/__regex/ecma_parser.h
+++ b/libcxx/include/__regex/ecma_parser.h
@@ -10,229 +10,295 @@
#define _LIBCPP___REGEX_ECMA_PARSER_H
#include <__config>
+#include <__regex/interpreter.h>
#include <__regex/regex_error.h>
-#include <__regex/state_machine.h>
-
-#define _LIBCPP_PARSER_FUNCTION [[clang::preserve_none]]
_LIBCPP_BEGIN_NAMESPACE_STD
namespace __regex::__ecma {
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION bool
-__parse_disjunction(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last);
-
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION bool
-__parse_assertion(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- if (__first == __last)
- return false;
- switch (*__first) {
- case '^': {
- __machine.push_back(__state::__start_anchor);
- ++__first;
- return true;
- }
- case '$': {
- __machine.push_back(__state::__end_anchor);
- ++__first;
- return true;
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+class __parser {
+ __interpreter<_CharT, _Traits> __machine_;
+ _ForwardIterator __first_;
+ _ForwardIterator __last_;
+ regex_constants::syntax_option_type __flags_ = {};
+ uint8_t __marked_count_ = 0;
+ size_t __open_count_ = 0;
+
+ bool __parse_assertion() {
+ switch (*__first_) {
+ case '^':
+ if (__flags_ & regex_constants::multiline)
+ __machine_.__push_multiline_start_anchor();
+ else
+ __machine_.__push_start_anchor();
+ ++__first_;
+ return true;
+
+ case '$':
+ if (__flags_ & regex_constants::multiline)
+ __machine_.__push_multiline_end_anchor();
+ else
+ __machine_.__push_end_anchor();
+ ++__first_;
+ return true;
+
+ case '\\': {
+ auto __next = std::next(__first_);
+ if (__next == __last_)
+ return false;
+ switch (*__next) {
+ case 'b':
+ __machine_.__push_word_boundary();
+ break;
+
+ case 'B':
+ __machine_.__push_no_word_boundary();
+ break;
+
+ default:
+ return false;
+ }
+ __first_ = ++__next;
+ return true;
+ }
+
+ case '(': {
+ auto __next = std::next(__first_);
+ if (__next == __last_ || *__next != '?' || ++__next == __last_)
+ return false;
+ switch (*__next) {
+ case '=':
+ case '!': {
+ bool __is_positive = *__next == '=';
+ auto __lookahead_info = __machine_.__start_lookahead();
+ auto __marked_count = std::exchange(__marked_count_, 0);
+ __first_ = ++__next;
+ __parse_exp();
+ if (__first_ == __last_ || *__first_ != ')')
+ std::__throw_regex_error<regex_constants::error_paren>();
+ ++__first_;
+ __machine_.__push_lookahead(__is_positive, __lookahead_info, __marked_count, __marked_count_);
+ __marked_count_ += __marked_count;
+ return true;
+ }
+
+ default:
+ return false;
+ }
+ }
+
+ default:
+ return false;
+ }
}
- case '\\': {
- auto __next = std::next(__first);
- if (__next == __last)
+
+ bool __parse_pattern_character() {
+ switch (*__first_) {
+ case '^':
+ case '$':
+ case '\\':
+ case '.':
+ case '*':
+ case '+':
+ case '?':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '|':
return false;
- if (auto __char = *__next; __char == 'b' || __char == 'B') {
- __machine.push_back(__char == 'b' ? __state::__match_word_boundary : __state::__match_no_word_boundary);
- __first = ++__next;
+ default:
+ __machine_.__push_char_matcher(*__first_++);
return true;
}
- return false;
}
- case '(': {
- auto __next = std::next(__first);
- if (__next == __last || *++__next != '?' || __next == __last)
- return false;
- auto __char = *__next;
- if (__char != '=' && __char != '!')
- return false;
- __machine.push_back(__char == '=' ? __state::__positive_lookahead_start : __state::__negative_lookahead_start);
- if (!__ecma::__parse_disjunction(__machine, __first, __last))
+
+ bool __parse_decimal_escape() {
+ if (*__first_ == '0') {
+ __machine_.__push_char_matcher('\0');
+ ++__first_;
+ return true;
+ }
+
+ if (*__first_ < '1' || *__first_ > '9')
return false;
- __machine.push_back(__state::__lookahead_end);
- if (__first == __last || *__first++ != ')')
- std::__throw_regex_error<regex_constants::error_paren>();
- return true;
- }
- }
- return false;
-}
-
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION bool
-__parse_decimal_escape(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- if (*__first == '0') {
- __regex::__match_char(__machine, '\0');
- ++__first;
- return true;
- }
- if ('1' <= *__first && *__first <= '9') {
- unsigned __value = *__first - '0';
- for (++__first; __first != __last && '0' <= *__first && *__first <= '9'; ++__first) {
- if (__value >= numeric_limits<unsigned>::max() / 10)
+ size_t __val = *__first_ - '0';
+
+ for (++__first_; __first_ != __last_ && *__first_ >= '0' && *__first_ <= '0'; ++__first_) {
+ if (__val >= numeric_limits<size_t>::max() / 10)
std::__throw_regex_error<regex_constants::error_backref>();
- __value = __value * 10 + *__first - '0';
+ __val = 10 * __val + *__first_ - '0';
}
- if (__value == 0)
+ if (__val == 0 || __val > __marked_count_)
std::__throw_regex_error<regex_constants::error_backref>();
- __machine.push_back(__state::__match_backref);
- __regex::__write_uleb(__machine, __value);
+ __machine_.__push_backref_matcher(__val);
+ return true;
}
- return true;
-}
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION bool
-__parse_character_class_escape(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- if (__first == __last)
- return false;
- switch (*__first) {
- case 'd':
- __machine.push_back(__state::__match_digits);
- break;
- case 'D':
- __machine.push_back(__state::__match_no_digits);
- break;
- case 's':
- __machine.push_back(__state::__match_whitespace);
- break;
- case 'S':
- __machine.push_back(__state::__match_no_whitespace);
- break;
- case 'w':
- __machine.push_back(__state::__match_word_character);
- break;
- case 'W':
- __machine.push_back(__state::__match_no_word_character);
- break;
- default:
+ bool __parse_character_class_escape() {
+ __bracket_expr<_CharT, _Traits> __expr;
+ switch (*__first_) {
+ case 'd': {
+ ++__first_;
+ __expr.__mask_ = ctype_base::digit;
+ __machine_.__push_bracket_expr(false, __expr);
+ return true;
+ }
+
+ case 'D': {
+ ++__first_;
+ __expr.__mask_ = ctype_base::digit;
+ __machine_.__push_bracket_expr(true, __expr);
+ return true;
+ }
+
+ case 's': {
+ ++__first_;
+ __expr.__mask_ = ctype_base::space;
+ __machine_.__push_bracket_expr(false, __expr);
+ return true;
+ }
+
+ case 'S': {
+ ++__first_;
+ __expr.__mask_ = ctype_base::space;
+ __machine_.__push_bracket_expr(true, __expr);
+ return true;
+ }
+
+ case 'w': {
+ ++__first_;
+ __expr.__mask_ = ctype_base::alnum;
+ __machine_.__push_bracket_expr(false, __expr);
+ return true;
+ }
+
+ case 'W': {
+ ++__first_;
+ __expr.__mask_ = ctype_base::alnum;
+ __machine_.__push_bracket_expr(true, __expr);
+ return true;
+ }
+ }
return false;
}
- ++__first;
- return true;
-}
-
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION bool
-__parse_character_escape(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- if (__first == __last)
- return false;
- switch (*__first) {
- case 'f':
- __regex::__match_char(__machine, '\f');
- break;
- case 'n':
- __regex::__match_char(__machine, '\n');
- break;
- case 'r':
- __regex::__match_char(__machine, '\r');
- break;
- case 't':
- __regex::__match_char(__machine, '\t');
- break;
- case 'v':
- __regex::__match_char(__machine, '\v');
- break;
-
- case 'c': {
- auto __next = std::next(__first);
- if (__next == __last)
- std::__throw_regex_error<regex_constants::error_escape>();
- if (('A' <= *__next && *__next <= 'Z') || ('a' <= *__next && *__next <= 'z')) {
- __regex::__match_char(__machine, *__next % 32);
- __first += ++__next;
- } else {
- std::__throw_regex_error<regex_constants::error_escape>();
+
+ bool __parse_atom() {
+ switch (*__first_) {
+ case '.':
+ __machine_.__push_any_except_newline_matcher();
+ ++__first_;
+ return true;
+
+ case '\\': {
+ ++__first_;
+ if (__first_ == __last_)
+ std::__throw_regex_error<regex_constants::error_escape>();
+
+ if (__parse_decimal_escape())
+ return true;
+
+ if (__parse_character_class_escape())
+ return true;
+
+ __machine_.__push_char_matcher(__regex::__parse_character_escape(__machine_, __first_, __last_));
+ return true;
}
- }
- }
- ++__first;
- return true;
-}
-
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION bool
-__parse_atom_escape(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- _LIBCPP_ASSERT_INTERNAL(*__first == '\\', "Parsing escape character without an escape start?");
- auto __next = std::next(__first);
- if (__next == __last)
- std::__throw_regex_error<regex_constants::error_escape>();
-
- if (__ecma::__parse_decimal_escape(__machine, __next, __last) ||
- __ecma::__parse_character_class_escape(__machine, __next, __last)) {
- __first = __next;
- return true;
- }
- return false;
-}
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION bool
-__parse_atom(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- if (__first == __last)
- return false;
+ case '[':
+ return __parse_bracket_expression(__machine_, __first_, __last_, __flags_);
- switch (*__first) {
- case '.': {
- __machine.push_back(__state::__match_any);
- ++__first;
- return true;
- }
- case '\\':
- return __ecma::__parse_atom_escape(__machine, __first, __last);
+ case '(': {
+ ++__first_;
+ if (__first_ == __last_)
+ std::__throw_regex_error<regex_constants::error_paren>();
+ auto __next = std::next(__first_);
+
+ bool __explicit_unmarked = (__next != __last_ && *__first_ == '?' && *__next == ':');
+ bool __marked = !(__flags_ & regex_constants::nosubs) && !__explicit_unmarked;
+ auto __subexpr_num = __marked_count_;
+
+ if (__marked) {
+ ++__marked_count_;
+ __machine_.__push_subexpression_begin(__subexpr_num);
+ } else if (__explicit_unmarked) {
+ __first_ = ++__next;
+ }
+
+ ++__open_count_;
+ __parse_exp();
+ if (__first_ == __last_ || *__first_ != ')')
+ std::__throw_regex_error<regex_constants::error_paren>();
+ --__open_count_;
+ ++__first_;
+ if (__marked)
+ __machine_.__push_subexpression_end(__subexpr_num);
+ return true;
+ }
+
+ case '*':
+ case '+':
+ case '?':
+ case '{':
+ std::__throw_regex_error<regex_constants::error_badrepeat>();
+
+ default:
+ return __parse_pattern_character();
+ }
}
- return false;
-}
+ bool __parse_term() {
+ if (__first_ == __last_)
+ return false;
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION bool
-__parse_term(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- return __ecma::__parse_assertion(__machine, __first, __last) || __ecma::__parse_atom(__machine, __first, __last);
-}
+ if (__parse_assertion())
+ return true;
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION void
-__parse_alternative(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- while (true) {
- __ecma::__parse_term(__machine, __first, __last);
+ size_t __expr_start = __machine_.size();
+
+ if (!__parse_atom())
+ return false;
+ __parse_dupl_symbol(__machine_, __first_, __last_, __expr_start, true);
+ return true;
}
-}
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION bool
-__parse_disjunction(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- while (__first != __last) {
- __ecma::__parse_alternative(__machine, __first, __last);
+ void __parse_alternative() {
+ while (__parse_term())
+ ;
}
- return true;
-}
-template <class _ForwardIterator>
-_LIBCPP_PARSER_FUNCTION void
-__parse_pattern(__state_machine& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
- __ecma::__parse_disjunction(__machine, __first, __last);
-}
+ void __parse_exp() {
+ auto __expr1_start = __machine_.size();
+ __parse_alternative();
-template <class _ForwardIterator>
-__state_machine __parse(_ForwardIterator __first, _ForwardIterator __last) {
- __state_machine __machine;
+ while (__first_ != __last_ && *__first_ == '|') {
+ ++__first_;
+ auto __expr2_start = __machine_.size();
+ __parse_alternative();
+ __machine_.__push_alternative(__expr1_start, __expr2_start);
+ }
+ }
- __ecma::__parse_pattern(__machine, __first, __last);
+public:
+ __parser(
+ _ForwardIterator __first, _ForwardIterator __last, _Traits __traits, regex_constants::syntax_option_type __flags)
+ : __machine_(__traits, false), __first_(__first), __last_(__last), __flags_(__flags) {}
+
+ void __parse_ecma() {
+ __parse_exp();
+ if (__first_ != __last_)
+ std::__throw_regex_error<regex_constants::__re_err_parse>();
+ __machine_.__push_end_state();
+ }
- return __machine;
-}
+ __interpreter<_CharT, _Traits> __extract_interpreter() { return std::move(__machine_); }
+ size_t mark_count() const { return __marked_count_; }
+};
} // namespace __regex::__ecma
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__regex/extended_parser.h b/libcxx/include/__regex/extended_parser.h
index 92906880eec44..76e2fa411a422 100644
--- a/libcxx/include/__regex/extended_parser.h
+++ b/libcxx/include/__regex/extended_parser.h
@@ -108,75 +108,6 @@ class __parser {
return __regex::__parse_bracket_expression(__machine_, __first_, __last_, __flags_);
}
- bool __parse_dupl_symbol(size_t __expr_start) {
- if (__first_ == __last_)
- return false;
- switch (*__first_) {
- case '*': {
- ++__first_;
- __machine_.__push_n_to_m_matcher(__expr_start, 0, numeric_limits<size_t>::max());
- } break;
-
- case '+': {
- ++__first_;
- __machine_.__push_n_to_m_matcher(__expr_start, 1, numeric_limits<size_t>::max());
- } break;
-
- case '?': {
- ++__first_;
- __machine_.__push_n_to_m_matcher(__expr_start, 0, 1);
- } break;
-
- case '{': {
- ++__first_;
- size_t __min;
- if (auto __res = __regex::__parse_dup_count(__first_, __last_)) {
- __min = __res.__num_;
- } else {
- std::__throw_regex_error<regex_constants::error_badbrace>();
- }
- if (__first_ == __last_)
- std::__throw_regex_error<regex_constants::error_brace>();
-
- switch (*__first_) {
- case '}': {
- ++__first_;
- __machine_.__push_n_matcher(__expr_start, __min);
- return true;
- } break;
-
- case ',': {
- ++__first_;
- if (__first_ == __last_)
- std::__throw_regex_error<regex_constants::error_badbrace>();
- if (*__first_ == '}') {
- ++__first_;
- __machine_.__push_n_to_m_matcher(__expr_start, __min, numeric_limits<size_t>::max());
- return true;
- }
-
- size_t __max;
- if (auto __res = __regex::__parse_dup_count(__first_, __last_)) {
- __max = __res.__num_;
- } else {
- std::__throw_regex_error<regex_constants::error_brace>();
- }
- if (__first_ == __last_ || *__first_ != '}')
- std::__throw_regex_error<regex_constants::error_brace>();
- ++__first_;
- if (__max < __min)
- std::__throw_regex_error<regex_constants::error_badbrace>();
- __machine_.__push_n_to_m_matcher(__expr_start, __min, __max);
- return true;
- } break;
- default:
- std::__throw_regex_error<regex_constants::error_badbrace>();
- }
- } break;
- }
- return false;
- }
-
bool __parse_expression() {
if (__first_ == __last_)
return false;
@@ -210,7 +141,7 @@ class __parser {
return false;
}
}
- __parse_dupl_symbol(__expr_start);
+ __regex::__parse_dupl_symbol(__machine_, __first_, __last_, __expr_start);
return true;
}
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 4bcff9d7c7f79..fc7aefa7db8a4 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -16,8 +16,7 @@
#include <__algorithm/transform.h>
#include <__config>
#include <__iterator/back_insert_iterator.h>
-#include <__ranges/filter_view.h>
-#include <__ranges/views.h>
+#include <__locale>
#include <__regex/regex_error.h>
#include <__utility/pair.h>
#include <__utility/to_underlying.h>
@@ -75,8 +74,11 @@ namespace __regex {
enum class __state : uint8_t {
__start_anchor,
__end_anchor,
+ __multiline_start_anchor,
+ __multiline_end_anchor,
__branch_alternative,
__match_any,
+ __match_any_except_newline,
__match_char,
__match_icase_char,
__match_backref,
@@ -86,8 +88,12 @@ enum class __state : uint8_t {
__marked_subexpression_begin,
__marked_subexpression_end,
__branch_n_to_m_matcher,
+ __branch_nongreedy_n_to_m_matcher,
__match_n_to_m_times,
- __match_n_times,
+ __match_word_boundary,
+ __match_no_word_boundary,
+ __positive_lookahead,
+ __negative_lookahead,
__relative_jump,
__end_state,
};
@@ -111,10 +117,12 @@ static_assert(sizeof(__interpreter_info<char>) == 1);
template <class _CharT, class _Traits>
struct __bracket_expr {
vector<_CharT> __chars_;
+ vector<_CharT> __neg_chars_;
vector<_CharT> __digraphs_;
vector<_CharT> __ranges_;
vector<typename _Traits::string_type> __equivalences_;
- typename _Traits::char_class_type __mask_ = 0;
+ typename _Traits::char_class_type __mask_ = 0;
+ typename _Traits::char_class_type __neg_mask_ = 0;
};
template <class _CharT, class _Traits>
@@ -124,7 +132,8 @@ class __interpreter {
_Traits __traits_;
bool __find_longest_;
- static size_t __read_uleb(const vector<__interpreter_info<_CharT> >& __machine, size_t& __current_pos) {
+ static pair<size_t, size_t>
+ __read_uleb_impl(_LIBCPP_NOESCAPE const __interpreter_info<_CharT>* __machine, size_t __current_pos) {
size_t __result = 0;
size_t __shift = 0;
@@ -134,261 +143,428 @@ class __interpreter {
__result |= (__byte & 0x7f) << __shift;
__shift += 7;
} while (__byte & 0x80);
- return __result;
+ return {__result, __current_pos};
+ }
+
+ static size_t __read_uleb(const __interpreter_info<_CharT>* __machine, size_t& __current_pos) {
+ auto __val = __machine[__current_pos++].__int_;
+ if (__val & 0x80) {
+ auto __res = __read_uleb_impl(__machine, __current_pos);
+ __current_pos = __res.second;
+ return __res.first;
+ }
+ return __val;
}
struct __global_execution_state {
struct __local_execution_state;
- bool __at_first_;
- stack<__local_execution_state> __states_;
+ vector<__local_execution_state> __states_;
const __interpreter& __machine_;
regex_constants::match_flag_type __flags_;
- size_t __counter_ = 0;
struct __local_execution_state {
const _CharT* __current_;
vector<sub_match<const _CharT*> > __sub_matches_;
size_t __current_pos_;
- vector<size_t> __loop_values_;
- vector<const _CharT*> __loop_starts_;
+ unique_ptr<size_t[]> __loop_values_;
+ unique_ptr<const _CharT*[]> __loop_starts_;
+
+ void __copy_to(const _CharT* const __current,
+ vector<__local_execution_state>& __vec,
+ __global_execution_state& __gstate) {
+ auto __loop_value_count = __gstate.__machine_.__initial_loop_values_.size();
+ auto __loop_values_copy = std::make_unique_for_overwrite<size_t[]>(__loop_value_count);
+ std::copy_n(__loop_values_.get(), __loop_value_count, __loop_values_copy.get());
+ auto __loop_starts_copy = std::make_unique_for_overwrite<const _CharT*[]>(__loop_value_count);
+ std::copy_n(__loop_starts_.get(), __loop_value_count, __loop_starts_copy.get());
+ __vec.emplace_back(
+ __current, __sub_matches_, __current_pos_, std::move(__loop_values_copy), std::move(__loop_starts_copy));
+ }
+
+ static bool __is_word_boundary(const _CharT* __first,
+ const _CharT* __last,
+ const _CharT* const __current,
+ __global_execution_state& __gstate) {
+ auto __is_word_char = [&](char __c) {
+ return __c == '_' || __gstate.__machine_.__traits_.isctype(__c, ctype_base::alnum);
+ };
+
+ if (__first == __last)
+ return false;
+
+ if (__current == __last) {
+ return !(__gstate.__flags_ & regex_constants::match_not_eow) && __is_word_char(__current[-1]);
+ }
+
+ if (__current == __first && !(__gstate.__flags_ & regex_constants::match_prev_avail)) {
+ return !(__gstate.__flags_ & regex_constants::match_not_bow) && __is_word_char(__current[0]);
+ }
+
+ return __is_word_char(__current[-1]) != __is_word_char(__current[0]);
+ }
+
+ struct __charlist_result {
+ bool __matched;
+ bool __matched_digraph;
+ size_t __new_pos;
+ };
+
+ static __charlist_result __exec_match_character_list(
+ const __interpreter_info<_CharT>* const __code,
+ const _CharT* const __last,
+ const _CharT* const __current,
+ const __global_execution_state& __gstate,
+ size_t __current_pos) {
+ static constexpr auto __buffer_size =
+ std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1));
+ _CharT __buffer[__buffer_size];
+ for (size_t __i = 0; __i != __buffer_size; ++__i)
+ __buffer[__i] = __code[__current_pos++].__char_;
+ typename _Traits::char_class_type __mask;
+ __builtin_memcpy(&__mask, __buffer, sizeof(typename _Traits::char_class_type));
+
+ for (size_t __i = 0; __i != __buffer_size; ++__i)
+ __buffer[__i] = __code[__current_pos++].__char_;
+ typename _Traits::char_class_type __neg_mask;
+ __builtin_memcpy(&__neg_mask, __buffer, sizeof(typename _Traits::char_class_type));
+
+ auto __chars = __read_uleb(__code, __current_pos);
+ auto __digraphs = __read_uleb(__code, __current_pos) * 2;
+ auto __ranges = __read_uleb(__code, __current_pos) * 4;
+ auto __neg_chars = __read_uleb(__code, __current_pos);
+ auto __equiv_count = __read_uleb(__code, __current_pos);
+ auto __equiv_size = __read_uleb(__code, __current_pos);
+
+ bool __found = false;
+
+ for (size_t __i = 0; __i != __chars; ++__i) {
+ if (__code[__current_pos + __i].__char_ == *__current) {
+ __found = true;
+ break;
+ }
+ }
+
+ __current_pos += __chars;
- bool __execute(const _CharT* __first, const _CharT* __last, __global_execution_state& __gstate) {
+ if (__found) {
+ __current_pos += __digraphs + __ranges + __neg_chars + __equiv_size;
+ return {true, false, __current_pos};
+ }
+
+ if (__current + 1 != __last) {
+ _CharT __vals[2] = {__current[0], __current[1]};
+
+ for (size_t __i = 0; __i != __digraphs; __i += 2) {
+ if (__code[__current_pos + __i].__char_ == __vals[0] &&
+ __code[__current_pos + __i + 1].__char_ == __vals[1]) {
+ __found = true;
+ break;
+ }
+ }
+ }
+
+ __current_pos += __digraphs;
+
+ if (__found) {
+ __current_pos += __ranges + __neg_chars + __equiv_size;
+ return {true, true, __current_pos};
+ }
+
+ auto __cmp = __gstate.__machine_.__traits_.transform(__current, __current + 1);
+ for (size_t __i = 0; __i != __ranges; __i += 4) {
+ _CharT __range_info[4];
+ std::transform(__gstate.__machine_.__machine_.begin() + __current_pos + __i,
+ __gstate.__machine_.__machine_.begin() + __current_pos + __i + 4,
+ __range_info,
+ [](__interpreter_info<_CharT> __val) { return __val.__char_; });
+ basic_string_view<_CharT> __min(__range_info, __range_info[1] == '\0' ? 1 : 2);
+ basic_string_view<_CharT> __max(__range_info + 2, __range_info[3] == '\0' ? 1 : 2);
+ if (__min <= __cmp && __cmp <= __max) {
+ __found = true;
+ break;
+ }
+ }
+
+ __current_pos += __ranges;
+
+ if (__found) {
+ __current_pos += __neg_chars + __equiv_size;
+ return {true, false, __current_pos};
+ }
+
+ if (__gstate.__machine_.__traits_.isctype(*__current, __mask)) {
+ return {true, false, __current_pos};
+ }
+
+ bool __none_match = true;
+ for (size_t __i = 0; __i != __neg_chars; ++__i) {
+ if (__code[__current_pos + __i].__char_ == *__current) {
+ __none_match = false;
+ break;
+ }
+ }
+
+ __current_pos += __neg_chars;
+
+ if (__none_match && __neg_mask != 0 && !__gstate.__machine_.__traits_.isctype(*__current, __neg_mask)) {
+ return {true, false, __current_pos};
+ }
+
+ if (__found) {
+ __current_pos += __equiv_size;
+ return {true, false, __current_pos};
+ }
+
+ auto __after_pos = __current_pos + __equiv_size;
+ auto __transformed = __gstate.__machine_.__traits_.transform_primary(__current, __current + 1);
+ for (size_t __i = 0; __i != __equiv_count; ++__i) {
+ auto __size = __read_uleb(__code, __current_pos);
+ basic_string<_CharT> __str;
+ std::transform(__code + __current_pos,
+ __code + __current_pos + __size,
+ std::back_inserter(__str),
+ [](__interpreter_info<_CharT> __v) { return __v.__char_; });
+ __current_pos += __size;
+ if (__transformed == __str) {
+ __found = true;
+ break;
+ }
+ }
+
+ __current_pos = __after_pos;
+
+ return {__found, false, __current_pos};
+ }
+
+ pair<bool, size_t> __exec_lookahead(
+ const _CharT* const __first,
+ const _CharT* const __last,
+ const __global_execution_state& __gstate,
+ const __interpreter_info<_CharT>* const __code,
+ size_t __current_pos,
+ bool __is_positive) {
+ auto __jump_offset = __read_uleb(__code, __current_pos);
+ auto __submatch_count = __read_uleb(__code, __current_pos);
+ auto __submatch_base = __read_uleb(__code, __current_pos);
+ auto __loop_count = __read_uleb(__code, __current_pos);
+
+ unique_ptr<size_t[]> __initial_loop_values = std::make_unique_for_overwrite<size_t[]>(__loop_count);
+
+ for (size_t __i = 0; __i != __loop_count; ++__i)
+ __initial_loop_values[__i] = __read_uleb(__code, __current_pos);
+
+ __global_execution_state __gexec_state{{}, __gstate.__machine_, __gstate.__flags_};
+ __gexec_state.__flags_ &= ~regex_constants::__full_match;
+ auto& __s = __gexec_state.__states_.emplace_back();
+ if (__loop_count > 0)
+ __s.__sub_matches_.resize(__submatch_count);
+ __s.__current_ = __current_;
+ __s.__loop_values_ = std::move(__initial_loop_values);
+ __s.__loop_starts_ = std::make_unique<const _CharT*[]>(__loop_count);
+ __s.__current_pos_ = __current_pos;
+ if (__gexec_state.__execute(__first, __last) != __is_positive)
+ return {false, __current_pos};
+ if (__is_positive) {
+ auto& __matched_state = __gexec_state.__states_.back();
+ std::copy(__matched_state.__sub_matches_.begin(),
+ __matched_state.__sub_matches_.end(),
+ __sub_matches_.begin() + __submatch_base);
+ }
+ __current_pos += __jump_offset;
+ return {true, __current_pos};
+ }
+
+ size_t __exec_branch_n_to_m_matcher(
+ __global_execution_state& __gstate,
+ const __interpreter_info<_CharT>* const __code,
+ const _CharT* const __current,
+ size_t __current_pos,
+ bool __is_greedy) {
+ auto __loop_index = __read_uleb(__code, __current_pos);
+ auto __again_pos_base = __current_pos;
+ auto __again_pos = __again_pos_base - __read_uleb(__code, __current_pos);
+ if (__loop_values_[__loop_index] > 0) {
+ --__loop_values_[__loop_index];
+ __current_pos = __again_pos;
+ return __current_pos;
+ }
+ if (__loop_starts_[__loop_index] != __current && __loop_values_[__loop_index + 1] > 0) {
+ --__loop_values_[__loop_index + 1];
+ __loop_starts_[__loop_index] = __current;
+ __copy_to(__current, __gstate.__states_, __gstate);
+ if (!__is_greedy) {
+ __gstate.__states_.back().__current_pos_ = __again_pos;
+ } else {
+ __gstate.__states_.back().__current_pos_ = __current_pos;
+ __current_pos = __again_pos;
+ }
+ return __current_pos;
+ }
+ return __current_pos;
+ }
+
+ pair<bool, size_t> __execute(const _CharT* __first, const _CharT* __last, __global_execution_state& __gstate) {
+ const __interpreter_info<_CharT>* const __code = __gstate.__machine().data();
+ auto __current_pos = __current_pos_;
+ auto __counter = 0;
+ auto __current = __current_;
+ auto __commit_current = std::__make_scope_guard([&] { __current_ = __current; });
while (true) {
- ++__gstate.__counter_;
- auto __st = __gstate.__machine()[__current_pos_++].__state_;
+ ++__counter;
+ auto __st = __code[__current_pos++].__state_;
switch (__st) {
using enum __state;
+ case __multiline_start_anchor:
+ if (!(__gstate.__flags_ & regex_constants::__at_first) && (__current[-1] == '\n' || __current[-1] == '\r'))
+ break;
+ [[__fallthrough__]];
case __start_anchor: {
- if (!__gstate.__at_first_ || __first != __current_)
- return false;
+ if (__gstate.__flags_ & regex_constants::match_not_bol ||
+ !(__gstate.__flags_ & regex_constants::__at_first) || __first != __current)
+ return {false, __counter};
} break;
+ case __multiline_end_anchor:
+ if (__current[0] == '\r' || __current[0] == '\n')
+ break;
+ [[__fallthrough__]];
case __end_anchor: {
- if (__current_ != __last)
- return false;
+ if (__gstate.__flags_ & regex_constants::match_not_eol || __current != __last)
+ return {false, __counter};
} break;
case __end_state: {
- return !(__gstate.__flags_ & regex_constants::match_flag_type::__full_match) || __current_ == __last;
+ return {(!(__gstate.__flags_ & regex_constants::match_not_null) || __current != __first) &&
+ (!(__gstate.__flags_ & regex_constants::match_flag_type::__full_match) || __current == __last),
+ __counter};
}
case __match_any: {
- if (__current_ == __last)
- return false;
- ++__current_;
+ if (__current == __last)
+ return {false, __counter};
+ ++__current;
+ } break;
+
+ case __match_any_except_newline: {
+ if (__current == __last || *__current == '\r' || *__current == '\n')
+ return {false, __counter};
+ if constexpr (__is_same(_CharT, wchar_t)) {
+ if (*__current == 0x2028 || *__current == 0x2029)
+ return {false, __counter};
+ }
+ ++__current;
} break;
case __match_char: {
- if (__current_ == __last || *__current_ != __gstate.__machine()[__current_pos_++].__char_)
- return false;
- ++__current_;
+ if (__current == __last || *__current != __code[__current_pos++].__char_)
+ return {false, __counter};
+ ++__current;
} break;
case __match_icase_char: {
- if (__current_ == __last || __gstate.__machine_.__traits_.translate_nocase(*__current_) !=
- __gstate.__machine()[__current_pos_++].__char_)
- return false;
- ++__current_;
+ if (__current == __last ||
+ __gstate.__machine_.__traits_.translate_nocase(*__current) != __code[__current_pos++].__char_)
+ return {false, __counter};
+ ++__current;
} break;
case __branch_alternative: {
- auto __offset = __read_uleb(__gstate.__machine(), __current_pos_);
- __gstate.__states_.push(*this);
- __current_pos_ += __offset;
+ auto __offset = __read_uleb(__code, __current_pos);
+ __copy_to(__current, __gstate.__states_, __gstate);
+ __gstate.__states_.back().__current_pos_ = __current_pos + __offset;
break;
}
case __relative_jump: {
- __current_pos_ += __read_uleb(__gstate.__machine(), __current_pos_);
+ __current_pos += __read_uleb(__code, __current_pos);
break;
}
- case __branch_n_to_m_matcher: {
- auto __loop_index = __read_uleb(__gstate.__machine(), __current_pos_);
- auto __again_pos_base = __current_pos_;
- auto __again_pos = __again_pos_base - __read_uleb(__gstate.__machine(), __current_pos_);
- if (__loop_values_[__loop_index] > 0) {
- --__loop_values_[__loop_index];
- __current_pos_ = __again_pos;
- break;
- }
- if (__loop_starts_[__loop_index] != __current_ && __loop_values_[__loop_index + 1] > 0) {
- --__loop_values_[__loop_index + 1];
- __loop_starts_[__loop_index] = __current_;
- __gstate.__states_.push(*this);
- __current_pos_ = __again_pos;
- break;
- }
- break;
- }
+ case __branch_n_to_m_matcher:
+ case __branch_nongreedy_n_to_m_matcher: {
+ __current_pos = __exec_branch_n_to_m_matcher(
+ __gstate, __code, __current, __current_pos, __st != __branch_nongreedy_n_to_m_matcher);
+ } break;
case __match_backref: {
- sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__gstate.__machine(), __current_pos_) - 1];
+ sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
if (!__match.matched)
- return false;
+ return {false, __counter};
auto __len = __match.second - __match.first;
- if (__last - __current_ < __len || !std::equal(__match.first, __match.second, __current_))
- return false;
+ if (__last - __current < __len || !std::equal(__match.first, __match.second, __current))
+ return {false, __counter};
- __current_ += __len;
+ __current += __len;
} break;
case __match_icase_backref: {
- sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__gstate.__machine(), __current_pos_) - 1];
+ sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
if (!__match.matched)
- return false;
+ return {false, __counter};
auto __len = __match.second - __match.first;
- if (__last - __current_ < __len)
- return false;
+ if (__last - __current < __len)
+ return {false, __counter};
for (ptrdiff_t __i = 0; __i != __len; ++__i) {
if (__gstate.__machine_.__traits_.translate_nocase(__match.first[__i]) !=
- __gstate.__machine_.__traits_.translate_nocase(__current_[__i]))
- return false;
+ __gstate.__machine_.__traits_.translate_nocase(__current[__i]))
+ return {false, __counter};
}
- __current_ += __len;
+ __current += __len;
} break;
case __match_character_list:
case __match_no_character_list: {
- if (__current_ == __last)
- return false;
- static const auto __buffer_size =
- std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1));
- _CharT __buffer[__buffer_size];
- for (size_t __i = 0; __i != __buffer_size; ++__i)
- __buffer[__i] = __gstate.__machine()[__current_pos_++].__char_;
- typename _Traits::char_class_type __mask;
- __builtin_memcpy(&__mask, __buffer, sizeof(typename _Traits::char_class_type));
-
- auto __chars = __read_uleb(__gstate.__machine(), __current_pos_);
- auto __digraphs = __read_uleb(__gstate.__machine(), __current_pos_) * 2;
- auto __ranges = __read_uleb(__gstate.__machine(), __current_pos_) * 4;
- auto __equiv_count = __read_uleb(__gstate.__machine(), __current_pos_);
- auto __equiv_size = __read_uleb(__gstate.__machine(), __current_pos_);
-
- bool __found = false;
-
- for (size_t __i = 0; __i != __chars; ++__i) {
- if (__gstate.__machine()[__current_pos_ + __i].__char_ == *__current_) {
- __found = true;
- break;
- }
- }
-
- __current_pos_ += __chars;
-
- if (__found) {
- __current_pos_ += __digraphs + __ranges + __equiv_size;
- ++__current_;
- if (__st == __match_no_character_list)
- return false;
- break;
- }
-
- if (__current_ + 1 != __last) {
- _CharT __vals[2] = {__current_[0], __current_[1]};
-
- for (size_t __i = 0; __i != __digraphs; __i += 2) {
- if (__gstate.__machine()[__current_pos_ + __i].__char_ == __vals[0] &&
- __gstate.__machine()[__current_pos_ + __i + 1].__char_ == __vals[1]) {
- __found = true;
- break;
- }
- }
- }
-
- __current_pos_ += __digraphs;
-
- if (__found) {
- __current_pos_ += __ranges + __equiv_size;
- __current_ += 2;
- if (__st == __match_no_character_list)
- return false;
- break;
- }
-
- auto __cmp = __gstate.__machine_.__traits_.transform(__current_, __current_ + 1);
- for (size_t __i = 0; __i != __ranges; __i += 4) {
- _CharT __range_info[4];
- std::transform(__gstate.__machine_.__machine_.begin() + __current_pos_ + __i,
- __gstate.__machine_.__machine_.begin() + __current_pos_ + __i + 4,
- __range_info,
- [](__interpreter_info<_CharT> __val) { return __val.__char_; });
- basic_string_view<_CharT> __min(__range_info, __range_info[1] == '\0' ? 1 : 2);
- basic_string_view<_CharT> __max(__range_info + 2, __range_info[3] == '\0' ? 1 : 2);
- if (__min <= __cmp && __cmp <= __max) {
- __found = true;
- __current_ += __cmp.size();
- break;
- }
- }
-
- __current_pos_ += __ranges;
-
- if (__found) {
- __current_pos_ += __equiv_size;
- if (__st == __match_no_character_list)
- return false;
- break;
- }
-
- if (__gstate.__machine_.__traits_.isctype(*__current_, __mask)) {
- ++__current_;
- if (__st == __match_no_character_list)
- return false;
- break;
- }
-
- auto __after_pos = __current_pos_ + __equiv_size;
- auto __transformed = __gstate.__machine_.__traits_.transform_primary(__current_, __current_ + 1);
- for (size_t __i = 0; __i != __equiv_count; ++__i) {
- auto __size = __read_uleb(__gstate.__machine(), __current_pos_);
- basic_string<_CharT> __str;
- std::transform(__gstate.__machine().begin() + __current_pos_,
- __gstate.__machine().begin() + __current_pos_ + __size,
- std::back_inserter(__str),
- [](__interpreter_info<_CharT> __v) { return __v.__char_; });
- __current_pos_ += __size;
- if (__transformed == __str) {
- __found = true;
- break;
- }
- }
-
- __current_pos_ = __after_pos;
-
- if (__found) {
- ++__current_;
- if (__st == __match_no_character_list)
- return false;
- break;
- }
-
- if (__st == __match_no_character_list) {
- ++__current_;
- break;
+ if (__current == __last)
+ return {false, __counter};
+ if (auto [__success, __digraph, __new_pos] =
+ __exec_match_character_list(__code, __last, __current, __gstate, __current_pos);
+ __success != (__st == __match_character_list))
+ return {false, __counter};
+ else {
+ __current_pos = __new_pos;
+ ++__current; // Swallow the matched character
+ if (__digraph)
+ ++__current; // Swallow the second character of a digraph
}
- return false;
-
} break;
case __marked_subexpression_begin: {
- auto __match = __read_uleb(__gstate.__machine(), __current_pos_);
- __sub_matches_[__match].first = __current_;
+ auto __match = __read_uleb(__code, __current_pos);
+ __sub_matches_[__match].first = __current;
} break;
case __marked_subexpression_end: {
- auto __match = __read_uleb(__gstate.__machine(), __current_pos_);
- __sub_matches_[__match].second = __current_;
+ auto __match = __read_uleb(__code, __current_pos);
+ __sub_matches_[__match].second = __current;
__sub_matches_[__match].matched = true;
} break;
+ case __match_word_boundary: {
+ if (!__is_word_boundary(__first, __last, __current, __gstate))
+ return {false, __counter};
+ } break;
+
+ case __match_no_word_boundary: {
+ if (__is_word_boundary(__first, __last, __current, __gstate))
+ return {false, __counter};
+ } break;
+
+ case __negative_lookahead:
+ case __positive_lookahead: {
+ if (auto __result =
+ __exec_lookahead(__first, __last, __gstate, __code, __current_pos, (__st == __positive_lookahead));
+ __result.first)
+ __current_pos = __result.second;
+ else
+ return {false, __counter};
+ } break;
+
default:
std::__libcpp_unreachable();
}
@@ -403,32 +579,38 @@ class __interpreter {
if (__machine_.__find_longest_) {
__local_execution_state __best_state;
bool __found_match = false;
+ size_t __gcounter = 0;
while (!__states_.empty()) {
- if (__counter_ / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
std::__throw_regex_error<regex_constants::error_complexity>();
- auto __state = std::move(__states_.top());
- __states_.pop();
- if (__state.__execute(__first, __last, *this)) {
+ auto __state = std::move(__states_.back());
+ __states_.pop_back();
+ auto [__success, __counter] = __state.__execute(__first, __last, *this);
+ __gcounter += __counter;
+ if (__success) {
if (!__found_match || __best_state.__current_ < __state.__current_)
__best_state = std::move(__state);
if (__best_state.__current_ == __last) {
- __states_.push(std::move(__best_state));
+ __states_.push_back(std::move(__best_state));
return true;
}
__found_match = true;
}
}
- __states_.push(std::move(__best_state));
+ __states_.push_back(std::move(__best_state));
return __found_match;
} else {
+ size_t __gcounter = 0;
while (!__states_.empty()) {
- if (__counter_ / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
std::__throw_regex_error<regex_constants::error_complexity>();
- auto __state = std::move(__states_.top());
- __states_.pop();
- if (__state.__execute(__first, __last, *this)) {
- __states_.push(std::move(__state));
+ auto __state = std::move(__states_.back());
+ __states_.pop_back();
+ if (auto [__success, __counter] = __state.__execute(__first, __last, *this); __success) {
+ __states_.push_back(std::move(__state));
return true;
+ } else {
+ __gcounter += __counter;
}
}
return false;
@@ -471,11 +653,16 @@ class __interpreter {
}
public:
- __interpreter(_Traits __traits, bool __find_longest) : __traits_(__traits), __find_longest_(__find_longest) {}
+ __interpreter(const _Traits& __traits, bool __find_longest) : __traits_(__traits), __find_longest_(__find_longest) {
+ __machine_.reserve(16);
+ }
void __push_any_matcher() { push_back(__state::__match_any); }
+ void __push_any_except_newline_matcher() { push_back(__state::__match_any_except_newline); }
void __push_end_state() { push_back(__state::__end_state); }
+ void __push_multiline_start_anchor() { push_back(__state::__multiline_start_anchor); }
void __push_start_anchor() { push_back(__state::__start_anchor); }
+ void __push_multiline_end_anchor() { push_back(__state::__multiline_end_anchor); }
void __push_end_anchor() { push_back(__state::__end_anchor); }
void __push_char_matcher(_CharT __char,
@@ -499,21 +686,12 @@ class __interpreter {
__write_uleb(*this, __num);
}
- void __push_n_matcher(size_t __expr_start, size_t __count) {
- vector<__interpreter_info<_CharT> > __buffer;
- __buffer.push_back(__state::__match_n_times);
- __write_uleb(__buffer, __count);
- __write_uleb(__buffer, __machine_.size() - __expr_start + 1);
- insert(__expr_start, __buffer);
- push_back(__state::__end_state);
- }
-
- void __push_n_to_m_matcher(size_t __expr_start, size_t __min, size_t __max) {
- vector<__interpreter_info<_CharT> > __buffer;
+ void __push_n_to_m_matcher(size_t __expr_start, size_t __min, size_t __max, bool __greedy = true) {
+ vector<__interpreter_info<_CharT>> __buffer;
__push_relative_jump(__buffer, size() - __expr_start);
insert(__expr_start, __buffer);
__expr_start += __buffer.size();
- push_back(__state::__branch_n_to_m_matcher);
+ push_back(__greedy ? __state::__branch_n_to_m_matcher : __state::__branch_nongreedy_n_to_m_matcher);
__write_uleb(__machine_, __initial_loop_values_.size());
__write_uleb(__machine_, size() - __expr_start);
__initial_loop_values_.push_back(__min);
@@ -544,6 +722,8 @@ class __interpreter {
_CharT __buffer[std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1))];
__builtin_memcpy(__buffer, &__expr.__mask_, sizeof(__buffer));
append_range(__buffer);
+ __builtin_memcpy(__buffer, &__expr.__neg_mask_, sizeof(__buffer));
+ append_range(__buffer);
basic_string<_CharT> __equivalences_buffer;
for (auto& __eq : __expr.__equivalences_)
@@ -551,33 +731,112 @@ class __interpreter {
__write_uleb(*this, __expr.__chars_.size());
__write_uleb(*this, __expr.__digraphs_.size() / 2);
__write_uleb(*this, __expr.__ranges_.size() / 4);
+ __write_uleb(*this, __expr.__neg_chars_.size());
__write_uleb(*this, __expr.__equivalences_.size());
__write_uleb(*this, __equivalences_buffer.size());
append_range(__expr.__chars_);
append_range(__expr.__digraphs_);
append_range(__expr.__ranges_);
+ append_range(__expr.__neg_chars_);
append_range(__equivalences_buffer);
}
+ void __push_word_boundary() { push_back(__state::__match_word_boundary); }
+ void __push_no_word_boundary() { push_back(__state::__match_no_word_boundary); }
+
+ struct __lookahead_info {
+ vector<size_t> __initial_loop_values_;
+ size_t __lookahead_start_;
+ };
+
+ __lookahead_info __start_lookahead() {
+ __lookahead_info __ret;
+ __ret.__initial_loop_values_ = std::move(__initial_loop_values_);
+ __ret.__lookahead_start_ = __machine_.size();
+ return __ret;
+ }
+
+ void __push_lookahead(bool __is_positive, __lookahead_info __info, size_t __marked_base, size_t __marked_count) {
+ __push_end_state();
+ vector<__interpreter_info<_CharT>> __buffer;
+ __buffer.push_back(__is_positive ? __state::__positive_lookahead : __state::__negative_lookahead);
+ __write_uleb(__buffer, __machine_.size() - __info.__lookahead_start_);
+ __write_uleb(__buffer, __marked_count);
+ __write_uleb(__buffer, __marked_base);
+ __write_uleb(__buffer, __initial_loop_values_.size());
+ for (size_t __val : __initial_loop_values_)
+ __write_uleb(__buffer, __val);
+ insert(__info.__lookahead_start_, __buffer);
+ }
+
size_t size() const { return __machine_.size(); }
- __global_execution_state __get_exec_state(
- vector<sub_match<const _CharT*>>& __sub_matches,
- const _CharT* __current,
- bool __at_first,
- regex_constants::match_flag_type __flags) const {
- typename __global_execution_state::__local_execution_state __base_state;
- __base_state.__sub_matches_ = __sub_matches;
- __base_state.__current_ = __current;
- __base_state.__loop_values_ = __initial_loop_values_;
- __base_state.__loop_starts_.resize(__initial_loop_values_.size());
+ pair<bool, const _CharT*>
+ __execute(regex_constants::match_flag_type __flags,
+ const _CharT* __first,
+ const _CharT* __last,
+ vector<sub_match<const _CharT*>>& __sub_matches) const {
+ using __local_state = typename __global_execution_state::__local_execution_state;
+ __local_state __base_state;
+ __base_state.__sub_matches_ = std::move(__sub_matches);
+ __base_state.__current_ = __first;
+ if (!__initial_loop_values_.empty()) {
+ __base_state.__loop_values_ = std::make_unique_for_overwrite<size_t[]>(__initial_loop_values_.size());
+ std::copy(__initial_loop_values_.begin(), __initial_loop_values_.end(), __base_state.__loop_values_.get());
+ __base_state.__loop_starts_ = std::make_unique<const _CharT*[]>(__initial_loop_values_.size());
+ }
__base_state.__current_pos_ = 0;
- stack<typename __global_execution_state::__local_execution_state> __s;
- __s.push(__base_state);
- return __global_execution_state{__at_first, __s, *this, __flags};
+
+ __global_execution_state __gexec_state{{}, *this, __flags};
+ auto [__base_state_matched, __gcounter] = __base_state.__execute(__first, __last, __gexec_state);
+
+ size_t __length = __last - __first + 1;
+ if (__gexec_state.__machine_.__find_longest_) {
+ __local_state __best_state = __base_state_matched ? std::move(__base_state) : __local_state{};
+ bool __found_match = __base_state_matched;
+ while (!__gexec_state.__states_.empty()) {
+ if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ std::__throw_regex_error<regex_constants::error_complexity>();
+ auto __state = std::move(__gexec_state.__states_.back());
+ __gexec_state.__states_.pop_back();
+ auto [__success, __counter] = __state.__execute(__first, __last, __gexec_state);
+ __gcounter += __counter;
+ if (__success) {
+ if (!__found_match || __best_state.__current_ < __state.__current_)
+ __best_state = std::move(__state);
+ if (__best_state.__current_ == __last) {
+ __sub_matches = std::move(__best_state.__sub_matches_);
+ return {true, __best_state.__current_};
+ }
+ __found_match = true;
+ }
+ }
+ if (!__found_match)
+ return {false, {}};
+ __sub_matches = std::move(__best_state.__sub_matches_);
+ return {true, __best_state.__current_};
+ } else {
+ if (__base_state_matched) {
+ __sub_matches = std::move(__base_state.__sub_matches_);
+ return {true, __base_state.__current_};
+ }
+ while (!__gexec_state.__states_.empty()) {
+ if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ std::__throw_regex_error<regex_constants::error_complexity>();
+ auto __state = std::move(__gexec_state.__states_.back());
+ __gexec_state.__states_.pop_back();
+ if (auto [__success, __counter] = __state.__execute(__first, __last, __gexec_state); __success) {
+ __sub_matches = std::move(__state.__sub_matches_);
+ return {true, __state.__current_};
+ } else {
+ __gcounter += __counter;
+ }
+ }
+ return {false, {}};
+ }
}
- _Traits __get_traits() { return __traits_; }
+ const _Traits& __get_traits() const { return __traits_; }
};
} // namespace __regex
diff --git a/libcxx/include/__regex/parser_common.h b/libcxx/include/__regex/parser_common.h
index 44b5ebd563f05..f7ea5418b0cc0 100644
--- a/libcxx/include/__regex/parser_common.h
+++ b/libcxx/include/__regex/parser_common.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef _LIBCPP___REGEX_ECMA_PARSER_H
-#define _LIBCPP___REGEX_ECMA_PARSER_H
+#ifndef _LIBCPP___REGEX_PARSER_COMMON_H
+#define _LIBCPP___REGEX_PARSER_COMMON_H
#include <__algorithm/search.h>
#include <__config>
@@ -68,6 +68,115 @@ _CharT __parse_awk_escape(_ForwardIterator& __first, _ForwardIterator __last) {
return _CharT(__val);
}
+template <class _CharT, class _Traits, class _ForwardIterator>
+_CharT __parse_character_escape(
+ __interpreter<_CharT, _Traits>& __machine, _ForwardIterator& __first, _ForwardIterator __last) {
+ auto __get_next_converted = [&](bool __advance = true) {
+ if (__first == __last)
+ std::__throw_regex_error<regex_constants::error_escape>();
+ auto __converted = __machine.__get_traits().value(*__first, 16);
+ if (__advance)
+ ++__first;
+ if (__converted == -1)
+ std::__throw_regex_error<regex_constants::error_escape>();
+ return __converted;
+ };
+
+ size_t __sum = 0;
+ switch (*__first) {
+ case 'f':
+ ++__first;
+ return '\f';
+ case 'n':
+ ++__first;
+ return '\n';
+ case 'r':
+ ++__first;
+ return '\r';
+ case 't':
+ ++__first;
+ return '\t';
+ case 'v':
+ ++__first;
+ return '\v';
+ case '0':
+ ++__first;
+ return '\0';
+
+ case 'c': {
+ auto __next = std::next(__first);
+ if (__next == __last || !((*__next >= 'A' && *__next <= 'Z') || (*__next >= 'a' && *__next <= 'z')))
+ std::__throw_regex_error<regex_constants::error_escape>();
+ __first = std::next(__next);
+ return _CharT(*__next & ~0x20);
+ }
+
+ case 'u': {
+ ++__first;
+ __sum = __get_next_converted();
+ __sum = __sum * 16 + __get_next_converted(false);
+ }
+ [[__fallthrough__]];
+ case 'x': {
+ ++__first;
+ __sum = __sum * 16 + __get_next_converted();
+ __sum = __sum * 16 + __get_next_converted();
+ return __sum;
+ }
+ default: {
+ if (__machine.__get_traits().isctype(*__first, ctype_base::alnum))
+ std::__throw_regex_error<regex_constants::error_escape>();
+ return *__first++;
+ }
+ }
+}
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+void __parse_class_escape(
+ __interpreter<_CharT, _Traits>& __machine,
+ _ForwardIterator& __first,
+ _ForwardIterator __last,
+ basic_string<_CharT>& __start_range,
+ __bracket_expr<_CharT, _Traits>& __buffer) {
+ switch (*__first) {
+ case '\0':
+ ++__first;
+ __start_range = '\0';
+ return;
+ case 'b':
+ ++__first;
+ __start_range = '\b';
+ return;
+ case 'd':
+ ++__first;
+ __buffer.__mask_ |= ctype_base::digit;
+ return;
+ case 'D':
+ ++__first;
+ __buffer.__neg_mask_ |= ctype_base::digit;
+ return;
+ case 's':
+ ++__first;
+ __buffer.__mask_ |= ctype_base::space;
+ return;
+ case 'S':
+ ++__first;
+ __buffer.__neg_mask_ |= ctype_base::space;
+ return;
+ case 'w':
+ ++__first;
+ __buffer.__mask_ |= ctype_base::alnum;
+ __buffer.__chars_.push_back('_');
+ return;
+ case 'W':
+ ++__first;
+ __buffer.__neg_mask_ |= ctype_base::alnum;
+ __buffer.__neg_chars_.push_back('_');
+ return;
+ }
+ __start_range = __regex::__parse_character_escape(__machine, __first, __last);
+}
+
// bracket expression parsing
template <class _CharT, class _Traits, class _ForwardIterator>
@@ -190,7 +299,18 @@ bool __parse_expression_term(
__grammar == regex_constants::awk && *__first == '\\') {
if (++__first == __last)
return false;
- __start_range = __parse_awk_escape<_CharT>(__first, __last);
+ __start_range = __regex::__parse_awk_escape<_CharT>(__first, __last);
+ } else if (__grammar == regex_constants::ECMAScript && *__first == '\\') {
+ if (++__first == __last)
+ return false;
+ __regex::__parse_class_escape<_CharT>(__machine, __first, __last, __start_range, __buffer);
+ if (__start_range.empty()) {
+ if (__first == __last)
+ return false;
+ if (*__first == '-')
+ std::__throw_regex_error<regex_constants::error_range>();
+ return true;
+ }
} else {
__start_range = *__first;
++__first;
@@ -236,10 +356,20 @@ bool __parse_expression_term(
if (++__first == __last)
return false;
__start_range = __parse_awk_escape<_CharT>(__first, __last);
+ } else if (__grammar == regex_constants::ECMAScript && *__first == '\\') {
+ if (++__first == __last)
+ return false;
+ __regex::__parse_class_escape(__machine, __first, __last, __end_range, __buffer);
+ if (__end_range.empty())
+ std::__throw_regex_error<regex_constants::error_range>();
} else {
__end_range = *__first;
++__first;
}
+ if (__start_range.size() == 1 && __end_range.size() == 1) {
+ if (char_traits<_CharT>::lt(__end_range[0], __start_range[0]))
+ std::__throw_regex_error<regex_constants::error_range>();
+ }
__buffer.__ranges_.push_back(__start_range[0]);
__buffer.__ranges_.push_back(__start_range.size() == 2 ? __start_range[1] : '\0');
__buffer.__ranges_.push_back(__end_range[0]);
@@ -329,6 +459,93 @@ __dup_count_result __parse_dup_count(_ForwardIterator& __first, _ForwardIterator
return __dup_count_result(__num, true);
}
+// duplication symbol parsing
+
+template <class _CharT, class _Traits, class _ForwardIterator>
+bool __parse_dupl_symbol(
+ __interpreter<_CharT, _Traits>& __machine,
+ _ForwardIterator& __first,
+ _ForwardIterator __last,
+ size_t __expr_start,
+ bool __has_nongreedy = false) {
+ if (__first == __last)
+ return false;
+
+ auto __check_greediness = [&]() {
+ if (!__has_nongreedy)
+ return true;
+ if (__first == __last || *__first != '?')
+ return true;
+ ++__first;
+ return false;
+ };
+
+ switch (*__first) {
+ case '*': {
+ ++__first;
+ __machine.__push_n_to_m_matcher(__expr_start, 0, numeric_limits<size_t>::max(), __check_greediness());
+ } break;
+
+ case '+': {
+ ++__first;
+ __machine.__push_n_to_m_matcher(__expr_start, 1, numeric_limits<size_t>::max(), __check_greediness());
+ } break;
+
+ case '?': {
+ ++__first;
+ __machine.__push_n_to_m_matcher(__expr_start, 0, 1, __check_greediness());
+ } break;
+
+ case '{': {
+ ++__first;
+ size_t __min;
+ if (auto __res = __regex::__parse_dup_count(__first, __last)) {
+ __min = __res.__num_;
+ } else {
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ }
+ if (__first == __last)
+ std::__throw_regex_error<regex_constants::error_brace>();
+
+ switch (*__first) {
+ case '}': {
+ ++__first;
+ __machine.__push_n_to_m_matcher(__expr_start, __min, __min);
+ return true;
+ } break;
+
+ case ',': {
+ ++__first;
+ if (__first == __last)
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ if (*__first == '}') {
+ ++__first;
+ __machine.__push_n_to_m_matcher(__expr_start, __min, numeric_limits<size_t>::max());
+ return true;
+ }
+
+ size_t __max;
+ if (auto __res = __regex::__parse_dup_count(__first, __last)) {
+ __max = __res.__num_;
+ } else {
+ std::__throw_regex_error<regex_constants::error_brace>();
+ }
+ if (__first == __last || *__first != '}')
+ std::__throw_regex_error<regex_constants::error_brace>();
+ ++__first;
+ if (__max < __min)
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ __machine.__push_n_to_m_matcher(__expr_start, __min, __max);
+ return true;
+ } break;
+ default:
+ std::__throw_regex_error<regex_constants::error_badbrace>();
+ }
+ } break;
+ }
+ return false;
+}
+
} // namespace __regex
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__regex/regex_error.h b/libcxx/include/__regex/regex_error.h
index ee7811cd8edbd..4bf29d74c7282 100644
--- a/libcxx/include/__regex/regex_error.h
+++ b/libcxx/include/__regex/regex_error.h
@@ -98,7 +98,8 @@ enum match_flag_type {
format_no_copy = 1 << 9,
format_first_only = 1 << 10,
__no_update_pos = 1 << 11,
- __full_match = 1 << 12
+ __full_match = 1 << 12,
+ __at_first = 1 << 13, // Only used behind an ABI firewall, so the value can be changed at any point.
};
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR match_flag_type operator~(match_flag_type __x) {
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 7f3449bd92500..654f02a5df4f4 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -824,6 +824,7 @@ typedef regex_token_iterator<wstring::const_iterator> wsregex_token_iterator;
# include <__memory/shared_ptr.h>
# include <__memory_resource/polymorphic_allocator.h>
# include <__regex/basic_parser.h>
+# include <__regex/ecma_parser.h>
# include <__regex/extended_parser.h>
# include <__regex/regex_error.h>
# include <__type_traits/is_swappable.h>
@@ -1269,2287 +1270,370 @@ void __empty_state<_CharT>::__exec(__state& __s) const {
__s.__node_ = this->first();
}
-// __empty_non_own_state
-
-template <class _CharT>
-class __empty_non_own_state : public __has_one_state<_CharT> {
- typedef __has_one_state<_CharT> base;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI explicit __empty_non_own_state(__node<_CharT>* __s) : base(__s) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT>
-void __empty_non_own_state<_CharT>::__exec(__state& __s) const {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->first();
-}
-
-// __repeat_one_loop
-
-template <class _CharT>
-class __repeat_one_loop : public __has_one_state<_CharT> {
- typedef __has_one_state<_CharT> base;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI explicit __repeat_one_loop(__node<_CharT>* __s) : base(__s) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT>
-void __repeat_one_loop<_CharT>::__exec(__state& __s) const {
- __s.__do_ = __state::__repeat;
- __s.__node_ = this->first();
-}
-
-// __owns_two_states
-
-template <class _CharT>
-class __owns_two_states : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- base* __second_;
+template <class _CharT, class _Traits>
+class __interpreter_state : public __empty_state<_CharT> {
+ __regex::__interpreter<_CharT, _Traits> __machine_;
public:
- _LIBCPP_HIDE_FROM_ABI explicit __owns_two_states(__node<_CharT>* __s1, base* __s2) : base(__s1), __second_(__s2) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual ~__owns_two_states();
+ _LIBCPP_HIDE_FROM_ABI __interpreter_state(__regex::__interpreter<_CharT, _Traits> __machine, __node<_CharT>* __s)
+ : __empty_state<_CharT>(__s), __machine_(std::move(__machine)) {}
- _LIBCPP_HIDE_FROM_ABI base* second() const { return __second_; }
- _LIBCPP_HIDE_FROM_ABI base*& second() { return __second_; }
+ _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __exec(__state<_CharT>& __state) const override {
+ auto __res = __machine_.__execute(
+ __state.__flags_ | (__state.__at_first_ ? regex_constants::__at_first : regex_constants::match_flag_type()),
+ __state.__first_,
+ __state.__last_,
+ __state.__sub_matches_);
+ __state.__do_ = __res.first ? std::__state<_CharT>::__end_state : std::__state<_CharT>::__reject;
+ __state.__current_ = __res.second;
+ }
};
-template <class _CharT>
-__owns_two_states<_CharT>::~__owns_two_states() {
- delete __second_;
-}
-
-// __loop
-
-template <class _CharT>
-class __loop : public __owns_two_states<_CharT> {
- typedef __owns_two_states<_CharT> base;
+template <class _CharT, class _Traits = regex_traits<_CharT> >
+class basic_regex;
- size_t __min_;
- size_t __max_;
- unsigned __loop_id_;
- unsigned __mexp_begin_;
- unsigned __mexp_end_;
- bool __greedy_;
+typedef basic_regex<char> regex;
+# if _LIBCPP_HAS_WIDE_CHARACTERS
+typedef basic_regex<wchar_t> wregex;
+# endif
+template <class _CharT, class _Traits>
+class _LIBCPP_PREFERRED_NAME(regex) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wregex)) basic_regex {
public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI explicit __loop(
- unsigned __loop_id,
- __node<_CharT>* __s1,
- __owns_one_state<_CharT>* __s2,
- unsigned __mexp_begin,
- unsigned __mexp_end,
- bool __greedy = true,
- size_t __min = 0,
- size_t __max = numeric_limits<size_t>::max())
- : base(__s1, __s2),
- __min_(__min),
- __max_(__max),
- __loop_id_(__loop_id),
- __mexp_begin_(__mexp_begin),
- __mexp_end_(__mexp_end),
- __greedy_(__greedy) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state& __s) const;
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec_split(bool __second, __state& __s) const;
+ // types:
+ typedef _CharT value_type;
+ typedef _Traits traits_type;
+ typedef typename _Traits::string_type string_type;
+ typedef regex_constants::syntax_option_type flag_type;
+ typedef typename _Traits::locale_type locale_type;
private:
- _LIBCPP_HIDE_FROM_ABI void __init_repeat(__state& __s) const {
- __s.__loop_data_[__loop_id_].second = __s.__current_;
- for (size_t __i = __mexp_begin_ - 1; __i != __mexp_end_ - 1; ++__i) {
- __s.__sub_matches_[__i].first = __s.__last_;
- __s.__sub_matches_[__i].second = __s.__last_;
- __s.__sub_matches_[__i].matched = false;
- }
- }
-};
-
-template <class _CharT>
-void __loop<_CharT>::__exec(__state& __s) const {
- if (__s.__do_ == __state::__repeat) {
- bool __do_repeat = ++__s.__loop_data_[__loop_id_].first < __max_;
- bool __do_alt = __s.__loop_data_[__loop_id_].first >= __min_;
- if (__do_repeat && __do_alt && __s.__loop_data_[__loop_id_].second == __s.__current_)
- __do_repeat = false;
- if (__do_repeat && __do_alt)
- __s.__do_ = __state::__split;
- else if (__do_repeat) {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->first();
- __init_repeat(__s);
- } else {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->second();
- }
- } else {
- __s.__loop_data_[__loop_id_].first = 0;
- bool __do_repeat = 0 < __max_;
- bool __do_alt = 0 >= __min_;
- if (__do_repeat && __do_alt)
- __s.__do_ = __state::__split;
- else if (__do_repeat) {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->first();
- __init_repeat(__s);
- } else {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->second();
- }
- }
-}
-
-template <class _CharT>
-void __loop<_CharT>::__exec_split(bool __second, __state& __s) const {
- __s.__do_ = __state::__accept_but_not_consume;
- if (__greedy_ != __second) {
- __s.__node_ = this->first();
- __init_repeat(__s);
- } else
- __s.__node_ = this->second();
-}
-
-// __alternate
-
-template <class _CharT>
-class __alternate : public __owns_two_states<_CharT> {
- typedef __owns_two_states<_CharT> base;
+ _Traits __traits_;
+ flag_type __flags_;
+ unsigned __marked_count_;
+ unsigned __loop_count_;
+ int __open_count_;
+ shared_ptr<__empty_state<_CharT> > __start_;
+ __owns_one_state<_CharT>* __end_;
-public:
typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI explicit __alternate(__owns_one_state<_CharT>* __s1, __owns_one_state<_CharT>* __s2)
- : base(__s1, __s2) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state& __s) const;
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec_split(bool __second, __state& __s) const;
-};
-
-template <class _CharT>
-void __alternate<_CharT>::__exec(__state& __s) const {
- __s.__do_ = __state::__split;
-}
-
-template <class _CharT>
-void __alternate<_CharT>::__exec_split(bool __second, __state& __s) const {
- __s.__do_ = __state::__accept_but_not_consume;
- if (__second)
- __s.__node_ = this->second();
- else
- __s.__node_ = this->first();
-}
-
-// __begin_marked_subexpression
-
-template <class _CharT>
-class __begin_marked_subexpression : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- unsigned __mexp_;
+ typedef std::__node<_CharT> __node;
public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI explicit __begin_marked_subexpression(unsigned __mexp, __node<_CharT>* __s)
- : base(__s), __mexp_(__mexp) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT>
-void __begin_marked_subexpression<_CharT>::__exec(__state& __s) const {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__sub_matches_[__mexp_ - 1].first = __s.__current_;
- __s.__node_ = this->first();
-}
-
-// __end_marked_subexpression
+ // constants:
+ static const regex_constants::syntax_option_type icase = regex_constants::icase;
+ static const regex_constants::syntax_option_type nosubs = regex_constants::nosubs;
+ static const regex_constants::syntax_option_type optimize = regex_constants::optimize;
+ static const regex_constants::syntax_option_type collate = regex_constants::collate;
+ static const regex_constants::syntax_option_type ECMAScript = regex_constants::ECMAScript;
+ static const regex_constants::syntax_option_type basic = regex_constants::basic;
+ static const regex_constants::syntax_option_type extended = regex_constants::extended;
+ static const regex_constants::syntax_option_type awk = regex_constants::awk;
+ static const regex_constants::syntax_option_type grep = regex_constants::grep;
+ static const regex_constants::syntax_option_type egrep = regex_constants::egrep;
+ static const regex_constants::syntax_option_type multiline = regex_constants::multiline;
-template <class _CharT>
-class __end_marked_subexpression : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
+ // construct/copy/destroy:
+ _LIBCPP_HIDE_FROM_ABI basic_regex()
+ : __flags_(regex_constants::ECMAScript),
+ __marked_count_(0),
+ __loop_count_(0),
+ __open_count_(0),
+ __end_(nullptr) {}
+ _LIBCPP_HIDE_FROM_ABI explicit basic_regex(const value_type* __p, flag_type __f = regex_constants::ECMAScript)
+ : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
+ __init(__p, __p + __traits_.length(__p));
+ }
- unsigned __mexp_;
+ _LIBCPP_HIDE_FROM_ABI basic_regex(const value_type* __p, size_t __len, flag_type __f = regex_constants::ECMAScript)
+ : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
+ __init(__p, __p + __len);
+ }
-public:
- typedef std::__state<_CharT> __state;
+ // basic_regex(const basic_regex&) = default;
+ // basic_regex(basic_regex&&) = default;
+ template <class _ST, class _SA>
+ _LIBCPP_HIDE_FROM_ABI explicit basic_regex(const basic_string<value_type, _ST, _SA>& __p,
+ flag_type __f = regex_constants::ECMAScript)
+ : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
+ __init(__p.begin(), __p.end());
+ }
- _LIBCPP_HIDE_FROM_ABI explicit __end_marked_subexpression(unsigned __mexp, __node<_CharT>* __s)
- : base(__s), __mexp_(__mexp) {}
+ template <class _ForwardIterator>
+ _LIBCPP_HIDE_FROM_ABI
+ basic_regex(_ForwardIterator __first, _ForwardIterator __last, flag_type __f = regex_constants::ECMAScript)
+ : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
+ __init(__first, __last);
+ }
+# ifndef _LIBCPP_CXX03_LANG
+ _LIBCPP_HIDE_FROM_ABI basic_regex(initializer_list<value_type> __il, flag_type __f = regex_constants::ECMAScript)
+ : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
+ __init(__il.begin(), __il.end());
+ }
+# endif // _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
+ // ~basic_regex() = default;
-template <class _CharT>
-void __end_marked_subexpression<_CharT>::__exec(__state& __s) const {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__sub_matches_[__mexp_ - 1].second = __s.__current_;
- __s.__sub_matches_[__mexp_ - 1].matched = true;
- __s.__node_ = this->first();
-}
+ // basic_regex& operator=(const basic_regex&) = default;
+ // basic_regex& operator=(basic_regex&&) = default;
+ _LIBCPP_HIDE_FROM_ABI basic_regex& operator=(const value_type* __p) { return assign(__p); }
+# ifndef _LIBCPP_CXX03_LANG
+ _LIBCPP_HIDE_FROM_ABI basic_regex& operator=(initializer_list<value_type> __il) { return assign(__il); }
+# endif // _LIBCPP_CXX03_LANG
+ template <class _ST, class _SA>
+ _LIBCPP_HIDE_FROM_ABI basic_regex& operator=(const basic_string<value_type, _ST, _SA>& __p) {
+ return assign(__p);
+ }
-// __back_ref
+ // assign:
+ _LIBCPP_HIDE_FROM_ABI basic_regex& assign(const basic_regex& __that) { return *this = __that; }
+# ifndef _LIBCPP_CXX03_LANG
+ _LIBCPP_HIDE_FROM_ABI basic_regex& assign(basic_regex&& __that) _NOEXCEPT { return *this = std::move(__that); }
+# endif
+ _LIBCPP_HIDE_FROM_ABI basic_regex& assign(const value_type* __p, flag_type __f = regex_constants::ECMAScript) {
+ return assign(__p, __p + __traits_.length(__p), __f);
+ }
+ _LIBCPP_HIDE_FROM_ABI basic_regex&
+ assign(const value_type* __p, size_t __len, flag_type __f = regex_constants::ECMAScript) {
+ return assign(__p, __p + __len, __f);
+ }
+ template <class _ST, class _SA>
+ _LIBCPP_HIDE_FROM_ABI basic_regex&
+ assign(const basic_string<value_type, _ST, _SA>& __s, flag_type __f = regex_constants::ECMAScript) {
+ return assign(__s.begin(), __s.end(), __f);
+ }
-template <class _CharT>
-class __back_ref : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
+ template <class _InputIterator, __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI basic_regex&
+ assign(_InputIterator __first, _InputIterator __last, flag_type __f = regex_constants::ECMAScript) {
+ basic_string<_CharT> __t(__first, __last);
+ return assign(__t.begin(), __t.end(), __f);
+ }
- unsigned __mexp_;
+private:
+ _LIBCPP_HIDE_FROM_ABI void __member_init(flag_type __f) {
+ __flags_ = __f;
+ __marked_count_ = 0;
+ __loop_count_ = 0;
+ __open_count_ = 0;
+ __end_ = nullptr;
+ }
public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI explicit __back_ref(unsigned __mexp, __node<_CharT>* __s) : base(__s), __mexp_(__mexp) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT>
-void __back_ref<_CharT>::__exec(__state& __s) const {
- if (__mexp_ > __s.__sub_matches_.size())
- std::__throw_regex_error<regex_constants::error_backref>();
- sub_match<const _CharT*>& __sm = __s.__sub_matches_[__mexp_ - 1];
- if (__sm.matched) {
- ptrdiff_t __len = __sm.second - __sm.first;
- if (__s.__last_ - __s.__current_ >= __len && std::equal(__sm.first, __sm.second, __s.__current_)) {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__current_ += __len;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
+ template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI basic_regex&
+ assign(_ForwardIterator __first, _ForwardIterator __last, flag_type __f = regex_constants::ECMAScript) {
+ return assign(basic_regex(__first, __last, __f));
}
-}
-// __back_ref_icase
-
-template <class _CharT, class _Traits>
-class __back_ref_icase : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- _Traits __traits_;
- unsigned __mexp_;
+# ifndef _LIBCPP_CXX03_LANG
-public:
- typedef std::__state<_CharT> __state;
+ _LIBCPP_HIDE_FROM_ABI basic_regex&
+ assign(initializer_list<value_type> __il, flag_type __f = regex_constants::ECMAScript) {
+ return assign(__il.begin(), __il.end(), __f);
+ }
- _LIBCPP_HIDE_FROM_ABI explicit __back_ref_icase(const _Traits& __traits, unsigned __mexp, __node<_CharT>* __s)
- : base(__s), __traits_(__traits), __mexp_(__mexp) {}
+# endif // _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
+ // const operations:
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI unsigned mark_count() const { return __marked_count_; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI flag_type flags() const { return __flags_; }
-template <class _CharT, class _Traits>
-void __back_ref_icase<_CharT, _Traits>::__exec(__state& __s) const {
- sub_match<const _CharT*>& __sm = __s.__sub_matches_[__mexp_ - 1];
- if (__sm.matched) {
- ptrdiff_t __len = __sm.second - __sm.first;
- if (__s.__last_ - __s.__current_ >= __len) {
- for (ptrdiff_t __i = 0; __i < __len; ++__i) {
- if (__traits_.translate_nocase(__sm.first[__i]) != __traits_.translate_nocase(__s.__current_[__i]))
- goto __not_equal;
- }
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__current_ += __len;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
- } else {
- __not_equal:
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
+ // locale:
+ _LIBCPP_HIDE_FROM_ABI locale_type imbue(locale_type __loc) {
+ __member_init(ECMAScript);
+ __start_.reset();
+ return __traits_.imbue(__loc);
}
-}
-
-// __back_ref_collate
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI locale_type getloc() const { return __traits_.getloc(); }
-template <class _CharT, class _Traits>
-class __back_ref_collate : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- _Traits __traits_;
- unsigned __mexp_;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI explicit __back_ref_collate(const _Traits& __traits, unsigned __mexp, __node<_CharT>* __s)
- : base(__s), __traits_(__traits), __mexp_(__mexp) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT, class _Traits>
-void __back_ref_collate<_CharT, _Traits>::__exec(__state& __s) const {
- sub_match<const _CharT*>& __sm = __s.__sub_matches_[__mexp_ - 1];
- if (__sm.matched) {
- ptrdiff_t __len = __sm.second - __sm.first;
- if (__s.__last_ - __s.__current_ >= __len) {
- for (ptrdiff_t __i = 0; __i < __len; ++__i) {
- if (__traits_.translate(__sm.first[__i]) != __traits_.translate(__s.__current_[__i]))
- goto __not_equal;
- }
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__current_ += __len;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
- } else {
- __not_equal:
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-// __word_boundary
-
-template <class _CharT, class _Traits>
-class __word_boundary : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- _Traits __traits_;
- bool __invert_;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI explicit __word_boundary(const _Traits& __traits, bool __invert, __node<_CharT>* __s)
- : base(__s), __traits_(__traits), __invert_(__invert) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT, class _Traits>
-void __word_boundary<_CharT, _Traits>::__exec(__state& __s) const {
- bool __is_word_b = false;
- if (__s.__first_ != __s.__last_) {
- if (__s.__current_ == __s.__last_) {
- if (!(__s.__flags_ & regex_constants::match_not_eow)) {
- _CharT __c = __s.__current_[-1];
- __is_word_b = __c == '_' || __traits_.isctype(__c, ctype_base::alnum);
- }
- } else if (__s.__current_ == __s.__first_ && !(__s.__flags_ & regex_constants::match_prev_avail)) {
- if (!(__s.__flags_ & regex_constants::match_not_bow)) {
- _CharT __c = *__s.__current_;
- __is_word_b = __c == '_' || __traits_.isctype(__c, ctype_base::alnum);
- }
- } else {
- _CharT __c1 = __s.__current_[-1];
- _CharT __c2 = *__s.__current_;
- bool __is_c1_b = __c1 == '_' || __traits_.isctype(__c1, ctype_base::alnum);
- bool __is_c2_b = __c2 == '_' || __traits_.isctype(__c2, ctype_base::alnum);
- __is_word_b = __is_c1_b != __is_c2_b;
- }
- }
- if (__is_word_b != __invert_) {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-template <class _CharT, class _Traits>
-class __interpreter_state : public __owns_one_state<_CharT> {
- __regex::__interpreter<_CharT, _Traits> __machine_;
-
-public:
- _LIBCPP_HIDE_FROM_ABI __interpreter_state(__regex::__interpreter<_CharT, _Traits> __machine, __node<_CharT>* __s)
- : __owns_one_state<_CharT>(__s), __machine_(std::move(__machine)) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __exec(__state<_CharT>& __state) const override {
- auto __exec_state =
- __machine_.__get_exec_state(__state.__sub_matches_, __state.__current_, __state.__at_first_, __state.__flags_);
- if (!__exec_state.__execute(__state.__first_, __state.__last_)) {
- __state.__do_ = std::__state<_CharT>::__reject;
- __state.__node_ = nullptr;
- return;
- }
- __state.__do_ = std::__state<_CharT>::__end_state;
- auto& __matched_state = __exec_state.__states_.top();
- __state.__current_ = __matched_state.__current_;
- __state.__sub_matches_ = __matched_state.__sub_matches_;
- }
-};
-
-// __l_anchor
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool __is_eol(_CharT __c) {
- return __c == '\r' || __c == '\n';
-}
-
-template <class _CharT>
-class __l_anchor_multiline : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- bool __multiline_;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI __l_anchor_multiline(bool __multiline, __node<_CharT>* __s)
- : base(__s), __multiline_(__multiline) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT>
-void __l_anchor_multiline<_CharT>::__exec(__state& __s) const {
- if (__s.__at_first_ && __s.__current_ == __s.__first_ && !(__s.__flags_ & regex_constants::match_not_bol)) {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->first();
- } else if (__multiline_ && !__s.__at_first_ && std::__is_eol(*std::prev(__s.__current_))) {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-// __r_anchor
-
-template <class _CharT>
-class __r_anchor_multiline : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- bool __multiline_;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI __r_anchor_multiline(bool __multiline, __node<_CharT>* __s)
- : base(__s), __multiline_(__multiline) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT>
-void __r_anchor_multiline<_CharT>::__exec(__state& __s) const {
- if (__s.__current_ == __s.__last_ && !(__s.__flags_ & regex_constants::match_not_eol)) {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->first();
- } else if (__multiline_ && std::__is_eol(*__s.__current_)) {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-// __match_any
-
-template <class _CharT>
-class __match_any : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI __match_any(__node<_CharT>* __s) : base(__s) {}
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT>
-void __match_any<_CharT>::__exec(__state& __s) const {
- if (__s.__current_ != __s.__last_ && *__s.__current_ != 0) {
- __s.__do_ = __state::__accept_and_consume;
- ++__s.__current_;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-// __match_any_but_newline
-
-template <class _CharT>
-class __match_any_but_newline : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI __match_any_but_newline(__node<_CharT>* __s) : base(__s) {}
-
- void __exec(__state&) const override;
-};
-
-template <>
-_LIBCPP_EXPORTED_FROM_ABI void __match_any_but_newline<char>::__exec(__state&) const;
-# if _LIBCPP_HAS_WIDE_CHARACTERS
-template <>
-_LIBCPP_EXPORTED_FROM_ABI void __match_any_but_newline<wchar_t>::__exec(__state&) const;
-# endif
-
-// __match_char
-
-template <class _CharT>
-class __match_char : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- _CharT __c_;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI __match_char(_CharT __c, __node<_CharT>* __s) : base(__s), __c_(__c) {}
-
- __match_char(const __match_char&) = delete;
- __match_char& operator=(const __match_char&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT>
-void __match_char<_CharT>::__exec(__state& __s) const {
- if (__s.__current_ != __s.__last_ && *__s.__current_ == __c_) {
- __s.__do_ = __state::__accept_and_consume;
- ++__s.__current_;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-// __match_char_icase
-
-template <class _CharT, class _Traits>
-class __match_char_icase : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- _Traits __traits_;
- _CharT __c_;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI __match_char_icase(const _Traits& __traits, _CharT __c, __node<_CharT>* __s)
- : base(__s), __traits_(__traits), __c_(__traits.translate_nocase(__c)) {}
-
- __match_char_icase(const __match_char_icase&) = delete;
- __match_char_icase& operator=(const __match_char_icase&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT, class _Traits>
-void __match_char_icase<_CharT, _Traits>::__exec(__state& __s) const {
- if (__s.__current_ != __s.__last_ && __traits_.translate_nocase(*__s.__current_) == __c_) {
- __s.__do_ = __state::__accept_and_consume;
- ++__s.__current_;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-// __match_char_collate
-
-template <class _CharT, class _Traits>
-class __match_char_collate : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- _Traits __traits_;
- _CharT __c_;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI __match_char_collate(const _Traits& __traits, _CharT __c, __node<_CharT>* __s)
- : base(__s), __traits_(__traits), __c_(__traits.translate(__c)) {}
-
- __match_char_collate(const __match_char_collate&) = delete;
- __match_char_collate& operator=(const __match_char_collate&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT, class _Traits>
-void __match_char_collate<_CharT, _Traits>::__exec(__state& __s) const {
- if (__s.__current_ != __s.__last_ && __traits_.translate(*__s.__current_) == __c_) {
- __s.__do_ = __state::__accept_and_consume;
- ++__s.__current_;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-// __bracket_expression
-
-template <class _CharT, class _Traits>
-class __bracket_expression : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
- typedef typename _Traits::string_type string_type;
-
- _Traits __traits_;
- vector<_CharT> __chars_;
- vector<_CharT> __neg_chars_;
- vector<pair<string_type, string_type> > __ranges_;
- vector<pair<_CharT, _CharT> > __digraphs_;
- vector<string_type> __equivalences_;
- typename regex_traits<_CharT>::char_class_type __mask_;
- typename regex_traits<_CharT>::char_class_type __neg_mask_;
- bool __negate_;
- bool __icase_;
- bool __collate_;
- bool __might_have_digraph_;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI
- __bracket_expression(const _Traits& __traits, __node<_CharT>* __s, bool __negate, bool __icase, bool __collate)
- : base(__s),
- __traits_(__traits),
- __mask_(),
- __neg_mask_(),
- __negate_(__negate),
- __icase_(__icase),
- __collate_(__collate),
- __might_have_digraph_(__traits_.getloc().name() != "C") {}
-
- __bracket_expression(const __bracket_expression&) = delete;
- __bracket_expression& operator=(const __bracket_expression&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-
- _LIBCPP_HIDE_FROM_ABI bool __negated() const { return __negate_; }
-
- _LIBCPP_HIDE_FROM_ABI void __add_char(_CharT __c) {
- if (__icase_)
- __chars_.push_back(__traits_.translate_nocase(__c));
- else if (__collate_)
- __chars_.push_back(__traits_.translate(__c));
- else
- __chars_.push_back(__c);
- }
- _LIBCPP_HIDE_FROM_ABI void __add_neg_char(_CharT __c) {
- if (__icase_)
- __neg_chars_.push_back(__traits_.translate_nocase(__c));
- else if (__collate_)
- __neg_chars_.push_back(__traits_.translate(__c));
- else
- __neg_chars_.push_back(__c);
- }
- _LIBCPP_HIDE_FROM_ABI void __add_range(string_type __b, string_type __e) {
- if (__collate_) {
- if (__icase_) {
- for (size_t __i = 0; __i < __b.size(); ++__i)
- __b[__i] = __traits_.translate_nocase(__b[__i]);
- for (size_t __i = 0; __i < __e.size(); ++__i)
- __e[__i] = __traits_.translate_nocase(__e[__i]);
- } else {
- for (size_t __i = 0; __i < __b.size(); ++__i)
- __b[__i] = __traits_.translate(__b[__i]);
- for (size_t __i = 0; __i < __e.size(); ++__i)
- __e[__i] = __traits_.translate(__e[__i]);
- }
- __ranges_.push_back(
- std::make_pair(__traits_.transform(__b.begin(), __b.end()), __traits_.transform(__e.begin(), __e.end())));
- } else {
- if (__b.size() != 1 || __e.size() != 1 || char_traits<typename string_type::value_type>::lt(__e[0], __b[0]))
- std::__throw_regex_error<regex_constants::error_range>();
- if (__icase_) {
- __b[0] = __traits_.translate_nocase(__b[0]);
- __e[0] = __traits_.translate_nocase(__e[0]);
- }
- __ranges_.push_back(std::make_pair(std::move(__b), std::move(__e)));
- }
- }
- _LIBCPP_HIDE_FROM_ABI void __add_digraph(_CharT __c1, _CharT __c2) {
- if (__icase_)
- __digraphs_.push_back(std::make_pair(__traits_.translate_nocase(__c1), __traits_.translate_nocase(__c2)));
- else if (__collate_)
- __digraphs_.push_back(std::make_pair(__traits_.translate(__c1), __traits_.translate(__c2)));
- else
- __digraphs_.push_back(std::make_pair(__c1, __c2));
- }
- _LIBCPP_HIDE_FROM_ABI void __add_equivalence(const string_type& __s) { __equivalences_.push_back(__s); }
- _LIBCPP_HIDE_FROM_ABI void __add_class(typename regex_traits<_CharT>::char_class_type __mask) { __mask_ |= __mask; }
- _LIBCPP_HIDE_FROM_ABI void __add_neg_class(typename regex_traits<_CharT>::char_class_type __mask) {
- __neg_mask_ |= __mask;
- }
-};
-
-template <class _CharT, class _Traits>
-void __bracket_expression<_CharT, _Traits>::__exec(__state& __s) const {
- bool __found = false;
- unsigned __consumed = 0;
- if (__s.__current_ != __s.__last_) {
- ++__consumed;
- if (__might_have_digraph_) {
- const _CharT* __next = std::next(__s.__current_);
- if (__next != __s.__last_) {
- pair<_CharT, _CharT> __ch2(*__s.__current_, *__next);
- if (__icase_) {
- __ch2.first = __traits_.translate_nocase(__ch2.first);
- __ch2.second = __traits_.translate_nocase(__ch2.second);
- } else if (__collate_) {
- __ch2.first = __traits_.translate(__ch2.first);
- __ch2.second = __traits_.translate(__ch2.second);
- }
- if (!__traits_.lookup_collatename(std::addressof(__ch2.first), std::addressof(__ch2.first) + 2).empty()) {
- // __ch2 is a digraph in this locale
- ++__consumed;
- for (size_t __i = 0; __i < __digraphs_.size(); ++__i) {
- if (__ch2 == __digraphs_[__i]) {
- __found = true;
- goto __exit;
- }
- }
- if (__collate_ && !__ranges_.empty()) {
- string_type __s2 = __traits_.transform(std::addressof(__ch2.first), std::addressof(__ch2.first) + 2);
- for (size_t __i = 0; __i < __ranges_.size(); ++__i) {
- if (__ranges_[__i].first <= __s2 && __s2 <= __ranges_[__i].second) {
- __found = true;
- goto __exit;
- }
- }
- }
- if (!__equivalences_.empty()) {
- string_type __s2 =
- __traits_.transform_primary(std::addressof(__ch2.first), std::addressof(__ch2.first) + 2);
- for (size_t __i = 0; __i < __equivalences_.size(); ++__i) {
- if (__s2 == __equivalences_[__i]) {
- __found = true;
- goto __exit;
- }
- }
- }
- if (__traits_.isctype(__ch2.first, __mask_) && __traits_.isctype(__ch2.second, __mask_)) {
- __found = true;
- goto __exit;
- }
- if (!__traits_.isctype(__ch2.first, __neg_mask_) && !__traits_.isctype(__ch2.second, __neg_mask_)) {
- __found = true;
- goto __exit;
- }
- goto __exit;
- }
- }
- }
- // test *__s.__current_ as not a digraph
- _CharT __ch = *__s.__current_;
- if (__icase_)
- __ch = __traits_.translate_nocase(__ch);
- else if (__collate_)
- __ch = __traits_.translate(__ch);
- for (size_t __i = 0; __i < __chars_.size(); ++__i) {
- if (__ch == __chars_[__i]) {
- __found = true;
- goto __exit;
- }
- }
- // When there's at least one of __neg_chars_ and __neg_mask_, the set
- // of "__found" chars is
- // union(complement(union(__neg_chars_, __neg_mask_)),
- // other cases...)
- //
- // It doesn't make sense to check this when there are no __neg_chars_
- // and no __neg_mask_.
- if (!(__neg_mask_ == 0 && __neg_chars_.empty())) {
- const bool __in_neg_mask = __traits_.isctype(__ch, __neg_mask_);
- const bool __in_neg_chars = std::find(__neg_chars_.begin(), __neg_chars_.end(), __ch) != __neg_chars_.end();
- if (!(__in_neg_mask || __in_neg_chars)) {
- __found = true;
- goto __exit;
- }
- }
- if (!__ranges_.empty()) {
- string_type __s2 =
- __collate_ ? __traits_.transform(std::addressof(__ch), std::addressof(__ch) + 1) : string_type(1, __ch);
- for (size_t __i = 0; __i < __ranges_.size(); ++__i) {
- if (__ranges_[__i].first <= __s2 && __s2 <= __ranges_[__i].second) {
- __found = true;
- goto __exit;
- }
- }
- }
- if (!__equivalences_.empty()) {
- string_type __s2 = __traits_.transform_primary(std::addressof(__ch), std::addressof(__ch) + 1);
- for (size_t __i = 0; __i < __equivalences_.size(); ++__i) {
- if (__s2 == __equivalences_[__i]) {
- __found = true;
- goto __exit;
- }
- }
- }
- if (__traits_.isctype(__ch, __mask_)) {
- __found = true;
- goto __exit;
- }
- } else
- __found = __negate_; // force reject
-__exit:
- if (__found != __negate_) {
- __s.__do_ = __state::__accept_and_consume;
- __s.__current_ += __consumed;
- __s.__node_ = this->first();
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-template <class _CharT, class _Traits>
-class __lookahead;
-
-template <class _CharT, class _Traits = regex_traits<_CharT> >
-class basic_regex;
-
-typedef basic_regex<char> regex;
-# if _LIBCPP_HAS_WIDE_CHARACTERS
-typedef basic_regex<wchar_t> wregex;
-# endif
-
-template <class _CharT, class _Traits>
-class _LIBCPP_PREFERRED_NAME(regex) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wregex)) basic_regex {
-public:
- // types:
- typedef _CharT value_type;
- typedef _Traits traits_type;
- typedef typename _Traits::string_type string_type;
- typedef regex_constants::syntax_option_type flag_type;
- typedef typename _Traits::locale_type locale_type;
-
-private:
- _Traits __traits_;
- flag_type __flags_;
- unsigned __marked_count_;
- unsigned __loop_count_;
- int __open_count_;
- shared_ptr<__empty_state<_CharT> > __start_;
- __owns_one_state<_CharT>* __end_;
-
- typedef std::__state<_CharT> __state;
- typedef std::__node<_CharT> __node;
-
-public:
- // constants:
- static const regex_constants::syntax_option_type icase = regex_constants::icase;
- static const regex_constants::syntax_option_type nosubs = regex_constants::nosubs;
- static const regex_constants::syntax_option_type optimize = regex_constants::optimize;
- static const regex_constants::syntax_option_type collate = regex_constants::collate;
- static const regex_constants::syntax_option_type ECMAScript = regex_constants::ECMAScript;
- static const regex_constants::syntax_option_type basic = regex_constants::basic;
- static const regex_constants::syntax_option_type extended = regex_constants::extended;
- static const regex_constants::syntax_option_type awk = regex_constants::awk;
- static const regex_constants::syntax_option_type grep = regex_constants::grep;
- static const regex_constants::syntax_option_type egrep = regex_constants::egrep;
- static const regex_constants::syntax_option_type multiline = regex_constants::multiline;
-
- // construct/copy/destroy:
- _LIBCPP_HIDE_FROM_ABI basic_regex()
- : __flags_(regex_constants::ECMAScript),
- __marked_count_(0),
- __loop_count_(0),
- __open_count_(0),
- __end_(nullptr) {}
- _LIBCPP_HIDE_FROM_ABI explicit basic_regex(const value_type* __p, flag_type __f = regex_constants::ECMAScript)
- : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
- __init(__p, __p + __traits_.length(__p));
- }
-
- _LIBCPP_HIDE_FROM_ABI basic_regex(const value_type* __p, size_t __len, flag_type __f = regex_constants::ECMAScript)
- : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
- __init(__p, __p + __len);
- }
-
- // basic_regex(const basic_regex&) = default;
- // basic_regex(basic_regex&&) = default;
- template <class _ST, class _SA>
- _LIBCPP_HIDE_FROM_ABI explicit basic_regex(const basic_string<value_type, _ST, _SA>& __p,
- flag_type __f = regex_constants::ECMAScript)
- : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
- __init(__p.begin(), __p.end());
- }
-
- template <class _ForwardIterator>
- _LIBCPP_HIDE_FROM_ABI
- basic_regex(_ForwardIterator __first, _ForwardIterator __last, flag_type __f = regex_constants::ECMAScript)
- : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
- __init(__first, __last);
- }
-# ifndef _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI basic_regex(initializer_list<value_type> __il, flag_type __f = regex_constants::ECMAScript)
- : __flags_(__f), __marked_count_(0), __loop_count_(0), __open_count_(0), __end_(nullptr) {
- __init(__il.begin(), __il.end());
- }
-# endif // _LIBCPP_CXX03_LANG
-
- // ~basic_regex() = default;
-
- // basic_regex& operator=(const basic_regex&) = default;
- // basic_regex& operator=(basic_regex&&) = default;
- _LIBCPP_HIDE_FROM_ABI basic_regex& operator=(const value_type* __p) { return assign(__p); }
-# ifndef _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI basic_regex& operator=(initializer_list<value_type> __il) { return assign(__il); }
-# endif // _LIBCPP_CXX03_LANG
- template <class _ST, class _SA>
- _LIBCPP_HIDE_FROM_ABI basic_regex& operator=(const basic_string<value_type, _ST, _SA>& __p) {
- return assign(__p);
- }
-
- // assign:
- _LIBCPP_HIDE_FROM_ABI basic_regex& assign(const basic_regex& __that) { return *this = __that; }
-# ifndef _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI basic_regex& assign(basic_regex&& __that) _NOEXCEPT { return *this = std::move(__that); }
-# endif
- _LIBCPP_HIDE_FROM_ABI basic_regex& assign(const value_type* __p, flag_type __f = regex_constants::ECMAScript) {
- return assign(__p, __p + __traits_.length(__p), __f);
- }
- _LIBCPP_HIDE_FROM_ABI basic_regex&
- assign(const value_type* __p, size_t __len, flag_type __f = regex_constants::ECMAScript) {
- return assign(__p, __p + __len, __f);
- }
- template <class _ST, class _SA>
- _LIBCPP_HIDE_FROM_ABI basic_regex&
- assign(const basic_string<value_type, _ST, _SA>& __s, flag_type __f = regex_constants::ECMAScript) {
- return assign(__s.begin(), __s.end(), __f);
- }
-
- template <class _InputIterator, __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0>
- _LIBCPP_HIDE_FROM_ABI basic_regex&
- assign(_InputIterator __first, _InputIterator __last, flag_type __f = regex_constants::ECMAScript) {
- basic_string<_CharT> __t(__first, __last);
- return assign(__t.begin(), __t.end(), __f);
- }
-
-private:
- _LIBCPP_HIDE_FROM_ABI void __member_init(flag_type __f) {
- __flags_ = __f;
- __marked_count_ = 0;
- __loop_count_ = 0;
- __open_count_ = 0;
- __end_ = nullptr;
- }
-
-public:
- template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0>
- _LIBCPP_HIDE_FROM_ABI basic_regex&
- assign(_ForwardIterator __first, _ForwardIterator __last, flag_type __f = regex_constants::ECMAScript) {
- return assign(basic_regex(__first, __last, __f));
- }
-
-# ifndef _LIBCPP_CXX03_LANG
-
- _LIBCPP_HIDE_FROM_ABI basic_regex&
- assign(initializer_list<value_type> __il, flag_type __f = regex_constants::ECMAScript) {
- return assign(__il.begin(), __il.end(), __f);
- }
-
-# endif // _LIBCPP_CXX03_LANG
-
- // const operations:
- [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI unsigned mark_count() const { return __marked_count_; }
- [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI flag_type flags() const { return __flags_; }
-
- // locale:
- _LIBCPP_HIDE_FROM_ABI locale_type imbue(locale_type __loc) {
- __member_init(ECMAScript);
- __start_.reset();
- return __traits_.imbue(__loc);
- }
- [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI locale_type getloc() const { return __traits_.getloc(); }
-
- // swap:
- void swap(basic_regex& __r);
-
-private:
- _LIBCPP_HIDE_FROM_ABI unsigned __loop_count() const { return __loop_count_; }
-
- _LIBCPP_HIDE_FROM_ABI bool __use_multiline() const {
- return __get_grammar(__flags_) == ECMAScript && (__flags_ & multiline);
- }
-
- template <class _ForwardIterator>
- void __init(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_ERE_dupl_symbol(
- _ForwardIterator __first,
- _ForwardIterator __last,
- __owns_one_state<_CharT>* __s,
- unsigned __mexp_begin,
- unsigned __mexp_end);
- template <class _ForwardIterator>
- _ForwardIterator __parse_bracket_expression(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator
- __parse_follow_list(_ForwardIterator __first, _ForwardIterator __last, __bracket_expression<_CharT, _Traits>* __ml);
- template <class _ForwardIterator>
- _ForwardIterator __parse_expression_term(
- _ForwardIterator __first, _ForwardIterator __last, __bracket_expression<_CharT, _Traits>* __ml);
- template <class _ForwardIterator>
- _ForwardIterator __parse_equivalence_class(
- _ForwardIterator __first, _ForwardIterator __last, __bracket_expression<_CharT, _Traits>* __ml);
- template <class _ForwardIterator>
- _ForwardIterator __parse_character_class(
- _ForwardIterator __first, _ForwardIterator __last, __bracket_expression<_CharT, _Traits>* __ml);
- template <class _ForwardIterator>
- _ForwardIterator
- __parse_collating_symbol(_ForwardIterator __first, _ForwardIterator __last, basic_string<_CharT>& __col_sym);
- template <class _ForwardIterator>
- _ForwardIterator __parse_DUP_COUNT(_ForwardIterator __first, _ForwardIterator __last, int& __c);
- template <class _ForwardIterator>
- _ForwardIterator __parse_ecma_exp(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_alternative(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_term(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_assertion(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_atom(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_atom_escape(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_decimal_escape(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_character_class_escape(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator
- __parse_character_escape(_ForwardIterator __first, _ForwardIterator __last, basic_string<_CharT>* __str = nullptr);
- template <class _ForwardIterator>
- _ForwardIterator __parse_pattern_character(_ForwardIterator __first, _ForwardIterator __last);
- template <class _ForwardIterator>
- _ForwardIterator __parse_class_escape(
- _ForwardIterator __first,
- _ForwardIterator __last,
- basic_string<_CharT>& __str,
- __bracket_expression<_CharT, _Traits>* __ml);
- template <class _ForwardIterator>
- _ForwardIterator
- __parse_awk_escape(_ForwardIterator __first, _ForwardIterator __last, basic_string<_CharT>* __str = nullptr);
-
- bool __test_back_ref(_CharT);
-
- _LIBCPP_HIDE_FROM_ABI void __push_l_anchor();
- void __push_r_anchor();
- void __push_match_any();
- void __push_match_any_but_newline();
- _LIBCPP_HIDE_FROM_ABI void __push_greedy_inf_repeat(
- size_t __min, __owns_one_state<_CharT>* __s, unsigned __mexp_begin = 0, unsigned __mexp_end = 0) {
- __push_loop(__min, numeric_limits<size_t>::max(), __s, __mexp_begin, __mexp_end);
- }
- _LIBCPP_HIDE_FROM_ABI void __push_nongreedy_inf_repeat(
- size_t __min, __owns_one_state<_CharT>* __s, unsigned __mexp_begin = 0, unsigned __mexp_end = 0) {
- __push_loop(__min, numeric_limits<size_t>::max(), __s, __mexp_begin, __mexp_end, false);
- }
- void __push_loop(size_t __min,
- size_t __max,
- __owns_one_state<_CharT>* __s,
- size_t __mexp_begin = 0,
- size_t __mexp_end = 0,
- bool __greedy = true);
- __bracket_expression<_CharT, _Traits>* __start_matching_list(bool __negate);
- void __push_char(value_type __c);
- void __push_back_ref(int __i);
- void __push_alternation(__owns_one_state<_CharT>* __sa, __owns_one_state<_CharT>* __sb);
- void __push_begin_marked_subexpression();
- void __push_end_marked_subexpression(unsigned);
- void __push_empty();
- void __push_word_boundary(bool);
- void __push_lookahead(const basic_regex&, bool, unsigned);
-
- template <class _Allocator>
- bool __search(const _CharT* __first,
- const _CharT* __last,
- match_results<const _CharT*, _Allocator>& __m,
- regex_constants::match_flag_type __flags) const;
-
- template <class _Allocator>
- bool __match_at_start(
- vector<__state>& __states,
- const _CharT* __first,
- const _CharT* __last,
- match_results<const _CharT*, _Allocator>& __m,
- regex_constants::match_flag_type __flags,
- bool) const;
- template <class _Allocator>
- bool __match_at_start_ecma(
- vector<__state>& __states,
- const _CharT* __first,
- const _CharT* __last,
- match_results<const _CharT*, _Allocator>& __m,
- regex_constants::match_flag_type __flags,
- bool) const;
- template <class _Allocator>
- bool __match_at_start_posix_nosubs(
- const _CharT* __first,
- const _CharT* __last,
- match_results<const _CharT*, _Allocator>& __m,
- regex_constants::match_flag_type __flags,
- bool) const;
- template <class _Allocator>
- bool __match_at_start_posix_subs(
- vector<__state>& __states,
- const _CharT* __first,
- const _CharT* __last,
- match_results<const _CharT*, _Allocator>& __m,
- regex_constants::match_flag_type __flags,
- bool) const;
-
- template <class _Bp, class _Ap, class _Cp, class _Tp>
- friend bool
- regex_search(_Bp, _Bp, match_results<_Bp, _Ap>&, const basic_regex<_Cp, _Tp>&, regex_constants::match_flag_type);
-
- template <class _Ap, class _Cp, class _Tp>
- friend bool
- regex_search(const _Cp*,
- const _Cp*,
- match_results<const _Cp*, _Ap>&,
- const basic_regex<_Cp, _Tp>&,
- regex_constants::match_flag_type);
-
- template <class _Bp, class _Cp, class _Tp>
- friend bool regex_search(_Bp, _Bp, const basic_regex<_Cp, _Tp>&, regex_constants::match_flag_type);
-
- template <class _Cp, class _Tp>
- friend bool regex_search(const _Cp*, const _Cp*, const basic_regex<_Cp, _Tp>&, regex_constants::match_flag_type);
-
- template <class _Cp, class _Ap, class _Tp>
- friend bool regex_search(
- const _Cp*, match_results<const _Cp*, _Ap>&, const basic_regex<_Cp, _Tp>&, regex_constants::match_flag_type);
-
- template <class _ST, class _SA, class _Cp, class _Tp>
- friend bool regex_search(const basic_string<_Cp, _ST, _SA>& __s,
- const basic_regex<_Cp, _Tp>& __e,
- regex_constants::match_flag_type __flags);
-
- template <class _ST, class _SA, class _Ap, class _Cp, class _Tp>
- friend bool regex_search(const basic_string<_Cp, _ST, _SA>& __s,
- match_results<typename basic_string<_Cp, _ST, _SA>::const_iterator, _Ap>&,
- const basic_regex<_Cp, _Tp>& __e,
- regex_constants::match_flag_type __flags);
-
- template <class _Iter, class _Ap, class _Cp, class _Tp>
- friend bool
- regex_search(__wrap_iter<_Iter> __first,
- __wrap_iter<_Iter> __last,
- match_results<__wrap_iter<_Iter>, _Ap>& __m,
- const basic_regex<_Cp, _Tp>& __e,
- regex_constants::match_flag_type __flags);
-
- template <class, class>
- friend class __lookahead;
-};
-
-# if _LIBCPP_STD_VER >= 17
-template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0>
-basic_regex(_ForwardIterator, _ForwardIterator, regex_constants::syntax_option_type = regex_constants::ECMAScript)
- -> basic_regex<typename iterator_traits<_ForwardIterator>::value_type>;
-# endif
-
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::icase;
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::nosubs;
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::optimize;
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::collate;
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::ECMAScript;
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::basic;
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::extended;
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::awk;
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::grep;
-template <class _CharT, class _Traits>
-const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::egrep;
-
-template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::swap(basic_regex& __r) {
- using std::swap;
- swap(__traits_, __r.__traits_);
- swap(__flags_, __r.__flags_);
- swap(__marked_count_, __r.__marked_count_);
- swap(__loop_count_, __r.__loop_count_);
- swap(__open_count_, __r.__open_count_);
- swap(__start_, __r.__start_);
- swap(__end_, __r.__end_);
-}
-
-template <class _CharT, class _Traits>
-inline _LIBCPP_HIDE_FROM_ABI void swap(basic_regex<_CharT, _Traits>& __x, basic_regex<_CharT, _Traits>& __y) {
- return __x.swap(__y);
-}
-
-// __lookahead
-
-template <class _CharT, class _Traits>
-class __lookahead : public __owns_one_state<_CharT> {
- typedef __owns_one_state<_CharT> base;
-
- basic_regex<_CharT, _Traits> __exp_;
- unsigned __mexp_;
- bool __invert_;
-
-public:
- typedef std::__state<_CharT> __state;
-
- _LIBCPP_HIDE_FROM_ABI
- __lookahead(const basic_regex<_CharT, _Traits>& __exp, bool __invert, __node<_CharT>* __s, unsigned __mexp)
- : base(__s), __exp_(__exp), __mexp_(__mexp), __invert_(__invert) {}
-
- __lookahead(const __lookahead&) = delete;
- __lookahead& operator=(const __lookahead&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
-};
-
-template <class _CharT, class _Traits>
-void __lookahead<_CharT, _Traits>::__exec(__state& __s) const {
- match_results<const _CharT*> __m;
- __m.__init(1 + __exp_.mark_count(), __s.__current_, __s.__last_);
- vector<__state> __states_buffer;
- bool __matched = __exp_.__match_at_start_ecma(
- __states_buffer,
- __s.__current_,
- __s.__last_,
- __m,
- (__s.__flags_ | regex_constants::match_continuous) & ~regex_constants::__full_match,
- __s.__at_first_ && __s.__current_ == __s.__first_);
- if (__matched != __invert_) {
- __s.__do_ = __state::__accept_but_not_consume;
- __s.__node_ = this->first();
- for (unsigned __i = 1; __i < __m.size(); ++__i) {
- __s.__sub_matches_[__mexp_ + __i - 1] = __m.__matches_[__i];
- }
- } else {
- __s.__do_ = __state::__reject;
- __s.__node_ = nullptr;
- }
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-void basic_regex<_CharT, _Traits>::__init(_ForwardIterator __first, _ForwardIterator __last) {
- if (__get_grammar(__flags_) == 0)
- __flags_ |= regex_constants::ECMAScript;
- _ForwardIterator __temp = __parse(__first, __last);
- if (__temp != __last)
- std::__throw_regex_error<regex_constants::__re_err_parse>();
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse(_ForwardIterator __first, _ForwardIterator __last) {
- {
- unique_ptr<__node> __h(new __end_state<_CharT>);
- __start_.reset(new __empty_state<_CharT>(__h.get()));
- __h.release();
- __end_ = __start_.get();
- }
- switch (__get_grammar(__flags_)) {
- case ECMAScript:
- __first = __parse_ecma_exp(__first, __last);
- break;
- case basic:
- case grep: {
- __regex::__basic::__parser<_CharT, _Traits, _ForwardIterator> __parser(__first, __last, __traits_, flags());
- if (__get_grammar(__flags_) == basic)
- __parser.__parse_basic();
- else
- __parser.__parse_grep();
- __end_->first() = new __interpreter_state<_CharT, _Traits>(__parser.__extract_interpreter(), __end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
- __marked_count_ = __parser.mark_count();
- return __last;
- }
- case awk:
- case extended:
- case egrep: {
- __regex::__extended::__parser<_CharT, _Traits, _ForwardIterator> __parser(__first, __last, __traits_, flags());
- if (auto __grammar = __get_grammar(__flags_); __grammar == extended || __grammar == awk)
- __parser.__parse_extended();
- else
- __parser.__parse_egrep();
- __end_->first() = new __interpreter_state<_CharT, _Traits>(__parser.__extract_interpreter(), __end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
- __marked_count_ = __parser.mark_count();
- return __last;
- }
- default:
- std::__throw_regex_error<regex_constants::__re_err_grammar>();
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_ERE_dupl_symbol(
- _ForwardIterator __first,
- _ForwardIterator __last,
- __owns_one_state<_CharT>* __s,
- unsigned __mexp_begin,
- unsigned __mexp_end) {
- if (__first != __last) {
- unsigned __grammar = __get_grammar(__flags_);
- switch (*__first) {
- case '*':
- ++__first;
- if (__grammar == ECMAScript && __first != __last && *__first == '?') {
- ++__first;
- __push_nongreedy_inf_repeat(0, __s, __mexp_begin, __mexp_end);
- } else
- __push_greedy_inf_repeat(0, __s, __mexp_begin, __mexp_end);
- break;
- case '+':
- ++__first;
- if (__grammar == ECMAScript && __first != __last && *__first == '?') {
- ++__first;
- __push_nongreedy_inf_repeat(1, __s, __mexp_begin, __mexp_end);
- } else
- __push_greedy_inf_repeat(1, __s, __mexp_begin, __mexp_end);
- break;
- case '?':
- ++__first;
- if (__grammar == ECMAScript && __first != __last && *__first == '?') {
- ++__first;
- __push_loop(0, 1, __s, __mexp_begin, __mexp_end, false);
- } else
- __push_loop(0, 1, __s, __mexp_begin, __mexp_end);
- break;
- case '{': {
- int __min;
- _ForwardIterator __temp = __parse_DUP_COUNT(++__first, __last, __min);
- if (__temp == __first)
- std::__throw_regex_error<regex_constants::error_badbrace>();
- __first = __temp;
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_brace>();
- switch (*__first) {
- case '}':
- ++__first;
- if (__grammar == ECMAScript && __first != __last && *__first == '?') {
- ++__first;
- __push_loop(__min, __min, __s, __mexp_begin, __mexp_end, false);
- } else
- __push_loop(__min, __min, __s, __mexp_begin, __mexp_end);
- break;
- case ',':
- ++__first;
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_badbrace>();
- if (*__first == '}') {
- ++__first;
- if (__grammar == ECMAScript && __first != __last && *__first == '?') {
- ++__first;
- __push_nongreedy_inf_repeat(__min, __s, __mexp_begin, __mexp_end);
- } else
- __push_greedy_inf_repeat(__min, __s, __mexp_begin, __mexp_end);
- } else {
- int __max = -1;
- __temp = __parse_DUP_COUNT(__first, __last, __max);
- if (__temp == __first)
- std::__throw_regex_error<regex_constants::error_brace>();
- __first = __temp;
- if (__first == __last || *__first != '}')
- std::__throw_regex_error<regex_constants::error_brace>();
- ++__first;
- if (__max < __min)
- std::__throw_regex_error<regex_constants::error_badbrace>();
- if (__grammar == ECMAScript && __first != __last && *__first == '?') {
- ++__first;
- __push_loop(__min, __max, __s, __mexp_begin, __mexp_end, false);
- } else
- __push_loop(__min, __max, __s, __mexp_begin, __mexp_end);
- }
- break;
- default:
- std::__throw_regex_error<regex_constants::error_badbrace>();
- }
- } break;
- }
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_bracket_expression(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last && *__first == '[') {
- ++__first;
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_brack>();
- bool __negate = false;
- if (*__first == '^') {
- ++__first;
- __negate = true;
- }
- __bracket_expression<_CharT, _Traits>* __ml = __start_matching_list(__negate);
- // __ml owned by *this
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_brack>();
- if (__get_grammar(__flags_) != ECMAScript && *__first == ']') {
- __ml->__add_char(']');
- ++__first;
- }
- __first = __parse_follow_list(__first, __last, __ml);
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_brack>();
- if (*__first == '-') {
- __ml->__add_char('-');
- ++__first;
- }
- if (__first == __last || *__first != ']')
- std::__throw_regex_error<regex_constants::error_brack>();
- ++__first;
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_follow_list(
- _ForwardIterator __first, _ForwardIterator __last, __bracket_expression<_CharT, _Traits>* __ml) {
- if (__first != __last) {
- while (true) {
- _ForwardIterator __temp = __parse_expression_term(__first, __last, __ml);
- if (__temp == __first)
- break;
- __first = __temp;
- }
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_expression_term(
- _ForwardIterator __first, _ForwardIterator __last, __bracket_expression<_CharT, _Traits>* __ml) {
- if (__first != __last && *__first != ']') {
- _ForwardIterator __temp = std::next(__first);
- basic_string<_CharT> __start_range;
- if (__temp != __last && *__first == '[') {
- if (*__temp == '=')
- return __parse_equivalence_class(++__temp, __last, __ml);
- else if (*__temp == ':')
- return __parse_character_class(++__temp, __last, __ml);
- else if (*__temp == '.')
- __first = __parse_collating_symbol(++__temp, __last, __start_range);
- }
- unsigned __grammar = __get_grammar(__flags_);
- if (__start_range.empty()) {
- if ((__grammar == ECMAScript || __grammar == awk) && *__first == '\\') {
- if (__grammar == ECMAScript)
- __first = __parse_class_escape(++__first, __last, __start_range, __ml);
- else
- __first = __parse_awk_escape(++__first, __last, std::addressof(__start_range));
- } else {
- __start_range = *__first;
- ++__first;
- }
- }
- if (__first != __last && *__first != ']') {
- __temp = std::next(__first);
- if (__temp != __last && *__first == '-' && *__temp != ']') {
- // parse a range
- basic_string<_CharT> __end_range;
- __first = __temp;
- ++__temp;
- if (__temp != __last && *__first == '[' && *__temp == '.')
- __first = __parse_collating_symbol(++__temp, __last, __end_range);
- else {
- if ((__grammar == ECMAScript || __grammar == awk) && *__first == '\\') {
- if (__grammar == ECMAScript)
- __first = __parse_class_escape(++__first, __last, __end_range, __ml);
- else
- __first = __parse_awk_escape(++__first, __last, std::addressof(__end_range));
- } else {
- __end_range = *__first;
- ++__first;
- }
- }
- __ml->__add_range(std::move(__start_range), std::move(__end_range));
- } else if (!__start_range.empty()) {
- if (__start_range.size() == 1)
- __ml->__add_char(__start_range[0]);
- else
- __ml->__add_digraph(__start_range[0], __start_range[1]);
- }
- } else if (!__start_range.empty()) {
- if (__start_range.size() == 1)
- __ml->__add_char(__start_range[0]);
- else
- __ml->__add_digraph(__start_range[0], __start_range[1]);
- }
- }
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_class_escape(
- _ForwardIterator __first,
- _ForwardIterator __last,
- basic_string<_CharT>& __str,
- __bracket_expression<_CharT, _Traits>* __ml) {
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_escape>();
- switch (*__first) {
- case 0:
- __str = *__first;
- return ++__first;
- case 'b':
- __str = _CharT(8);
- return ++__first;
- case 'd':
- __ml->__add_class(ctype_base::digit);
- return ++__first;
- case 'D':
- __ml->__add_neg_class(ctype_base::digit);
- return ++__first;
- case 's':
- __ml->__add_class(ctype_base::space);
- return ++__first;
- case 'S':
- __ml->__add_neg_class(ctype_base::space);
- return ++__first;
- case 'w':
- __ml->__add_class(ctype_base::alnum);
- __ml->__add_char('_');
- return ++__first;
- case 'W':
- __ml->__add_neg_class(ctype_base::alnum);
- __ml->__add_neg_char('_');
- return ++__first;
- }
- __first = __parse_character_escape(__first, __last, std::addressof(__str));
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_awk_escape(
- _ForwardIterator __first, _ForwardIterator __last, basic_string<_CharT>* __str) {
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_escape>();
- switch (*__first) {
- case '\\':
- case '"':
- case '/':
- if (__str)
- *__str = *__first;
- else
- __push_char(*__first);
- return ++__first;
- case 'a':
- if (__str)
- *__str = _CharT(7);
- else
- __push_char(_CharT(7));
- return ++__first;
- case 'b':
- if (__str)
- *__str = _CharT(8);
- else
- __push_char(_CharT(8));
- return ++__first;
- case 'f':
- if (__str)
- *__str = _CharT(0xC);
- else
- __push_char(_CharT(0xC));
- return ++__first;
- case 'n':
- if (__str)
- *__str = _CharT(0xA);
- else
- __push_char(_CharT(0xA));
- return ++__first;
- case 'r':
- if (__str)
- *__str = _CharT(0xD);
- else
- __push_char(_CharT(0xD));
- return ++__first;
- case 't':
- if (__str)
- *__str = _CharT(0x9);
- else
- __push_char(_CharT(0x9));
- return ++__first;
- case 'v':
- if (__str)
- *__str = _CharT(0xB);
- else
- __push_char(_CharT(0xB));
- return ++__first;
- }
- if ('0' <= *__first && *__first <= '7') {
- unsigned __val = *__first - '0';
- if (++__first != __last && ('0' <= *__first && *__first <= '7')) {
- __val = 8 * __val + *__first - '0';
- if (++__first != __last && ('0' <= *__first && *__first <= '7'))
- __val = 8 * __val + *__first++ - '0';
- }
- if (__str)
- *__str = _CharT(__val);
- else
- __push_char(_CharT(__val));
- } else
- std::__throw_regex_error<regex_constants::error_escape>();
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_equivalence_class(
- _ForwardIterator __first, _ForwardIterator __last, __bracket_expression<_CharT, _Traits>* __ml) {
- // Found [=
- // This means =] must exist
- value_type __equal_close[2] = {'=', ']'};
- _ForwardIterator __temp = std::search(__first, __last, __equal_close, __equal_close + 2);
- if (__temp == __last)
- std::__throw_regex_error<regex_constants::error_brack>();
- // [__first, __temp) contains all text in [= ... =]
- string_type __collate_name = __traits_.lookup_collatename(__first, __temp);
- if (__collate_name.empty())
- std::__throw_regex_error<regex_constants::error_collate>();
- string_type __equiv_name = __traits_.transform_primary(__collate_name.begin(), __collate_name.end());
- if (!__equiv_name.empty())
- __ml->__add_equivalence(__equiv_name);
- else {
- switch (__collate_name.size()) {
- case 1:
- __ml->__add_char(__collate_name[0]);
- break;
- case 2:
- __ml->__add_digraph(__collate_name[0], __collate_name[1]);
- break;
- default:
- std::__throw_regex_error<regex_constants::error_collate>();
- }
- }
- __first = std::next(__temp, 2);
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_character_class(
- _ForwardIterator __first, _ForwardIterator __last, __bracket_expression<_CharT, _Traits>* __ml) {
- // Found [:
- // This means :] must exist
- value_type __colon_close[2] = {':', ']'};
- _ForwardIterator __temp = std::search(__first, __last, __colon_close, __colon_close + 2);
- if (__temp == __last)
- std::__throw_regex_error<regex_constants::error_brack>();
- // [__first, __temp) contains all text in [: ... :]
- typedef typename _Traits::char_class_type char_class_type;
- char_class_type __class_type = __traits_.lookup_classname(__first, __temp, __flags_ & icase);
- if (__class_type == 0)
- std::__throw_regex_error<regex_constants::error_ctype>();
- __ml->__add_class(__class_type);
- __first = std::next(__temp, 2);
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_collating_symbol(
- _ForwardIterator __first, _ForwardIterator __last, basic_string<_CharT>& __col_sym) {
- // Found [.
- // This means .] must exist
- value_type __dot_close[2] = {'.', ']'};
- _ForwardIterator __temp = std::search(__first, __last, __dot_close, __dot_close + 2);
- if (__temp == __last)
- std::__throw_regex_error<regex_constants::error_brack>();
- // [__first, __temp) contains all text in [. ... .]
- __col_sym = __traits_.lookup_collatename(__first, __temp);
- switch (__col_sym.size()) {
- case 1:
- case 2:
- break;
- default:
- std::__throw_regex_error<regex_constants::error_collate>();
- }
- __first = std::next(__temp, 2);
- return __first;
-}
-
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_DUP_COUNT(_ForwardIterator __first, _ForwardIterator __last, int& __c) {
- if (__first != __last) {
- int __val = __traits_.value(*__first, 10);
- if (__val != -1) {
- __c = __val;
- for (++__first; __first != __last && (__val = __traits_.value(*__first, 10)) != -1; ++__first) {
- if (__c >= numeric_limits<int>::max() / 10)
- std::__throw_regex_error<regex_constants::error_badbrace>();
- __c *= 10;
- __c += __val;
- }
- }
- }
- return __first;
-}
+ // swap:
+ void swap(basic_regex& __r);
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_ecma_exp(_ForwardIterator __first, _ForwardIterator __last) {
- __owns_one_state<_CharT>* __sa = __end_;
- _ForwardIterator __temp = __parse_alternative(__first, __last);
- if (__temp == __first)
- __push_empty();
- __first = __temp;
- while (__first != __last && *__first == '|') {
- __owns_one_state<_CharT>* __sb = __end_;
- __temp = __parse_alternative(++__first, __last);
- if (__temp == __first)
- __push_empty();
- __push_alternation(__sa, __sb);
- __first = __temp;
- }
- return __first;
-}
+private:
+ _LIBCPP_HIDE_FROM_ABI unsigned __loop_count() const { return __loop_count_; }
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_alternative(_ForwardIterator __first, _ForwardIterator __last) {
- while (true) {
- _ForwardIterator __temp = __parse_term(__first, __last);
- if (__temp == __first)
- break;
- __first = __temp;
- }
- return __first;
-}
+ template <class _ForwardIterator>
+ void __init(_ForwardIterator __first, _ForwardIterator __last);
+ template <class _ForwardIterator>
+ _ForwardIterator __parse(_ForwardIterator __first, _ForwardIterator __last);
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_term(_ForwardIterator __first, _ForwardIterator __last) {
- _ForwardIterator __temp = __parse_assertion(__first, __last);
- if (__temp == __first) {
- __owns_one_state<_CharT>* __e = __end_;
- unsigned __mexp_begin = __marked_count_;
- __temp = __parse_atom(__first, __last);
- if (__temp != __first)
- __first = __parse_ERE_dupl_symbol(__temp, __last, __e, __mexp_begin + 1, __marked_count_ + 1);
- } else
- __first = __temp;
- return __first;
-}
+ template <class _Allocator>
+ bool __search(const _CharT* __first,
+ const _CharT* __last,
+ match_results<const _CharT*, _Allocator>& __m,
+ regex_constants::match_flag_type __flags) const;
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_assertion(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- switch (*__first) {
- case '^':
- __push_l_anchor();
- ++__first;
- break;
- case '$':
- __push_r_anchor();
- ++__first;
- break;
- case '\\': {
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last) {
- if (*__temp == 'b') {
- __push_word_boundary(false);
- __first = ++__temp;
- } else if (*__temp == 'B') {
- __push_word_boundary(true);
- __first = ++__temp;
- }
- }
- } break;
- case '(': {
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last && *__temp == '?') {
- if (++__temp != __last) {
- switch (*__temp) {
- case '=': {
- basic_regex __exp;
- __exp.__flags_ = __flags_;
- __temp = __exp.__parse(++__temp, __last);
- unsigned __mexp = __exp.__marked_count_;
- __push_lookahead(std::move(__exp), false, __marked_count_);
- __marked_count_ += __mexp;
- if (__temp == __last || *__temp != ')')
- std::__throw_regex_error<regex_constants::error_paren>();
- __first = ++__temp;
- } break;
- case '!': {
- basic_regex __exp;
- __exp.__flags_ = __flags_;
- __temp = __exp.__parse(++__temp, __last);
- unsigned __mexp = __exp.__marked_count_;
- __push_lookahead(std::move(__exp), true, __marked_count_);
- __marked_count_ += __mexp;
- if (__temp == __last || *__temp != ')')
- std::__throw_regex_error<regex_constants::error_paren>();
- __first = ++__temp;
- } break;
- }
- }
- }
- } break;
- }
- }
- return __first;
-}
+ template <class _Allocator>
+ bool __match_at_start(
+ vector<__state>& __states,
+ const _CharT* __first,
+ const _CharT* __last,
+ match_results<const _CharT*, _Allocator>& __m,
+ regex_constants::match_flag_type __flags,
+ bool,
+ __interpreter_state<_CharT, _Traits>*) const;
+ template <class _Allocator>
+ bool __match_at_start_ecma(
+ vector<__state>& __states,
+ const _CharT* __first,
+ const _CharT* __last,
+ match_results<const _CharT*, _Allocator>& __m,
+ regex_constants::match_flag_type __flags,
+ bool) const;
+ template <class _Allocator>
+ bool __match_at_start_posix_nosubs(
+ const _CharT* __first,
+ const _CharT* __last,
+ match_results<const _CharT*, _Allocator>& __m,
+ regex_constants::match_flag_type __flags,
+ bool) const;
+ template <class _Allocator>
+ bool __match_at_start_posix_subs(
+ vector<__state>& __states,
+ const _CharT* __first,
+ const _CharT* __last,
+ match_results<const _CharT*, _Allocator>& __m,
+ regex_constants::match_flag_type __flags,
+ bool) const;
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_atom(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- switch (*__first) {
- case '.':
- __push_match_any_but_newline();
- ++__first;
- break;
- case '\\':
- __first = __parse_atom_escape(__first, __last);
- break;
- case '[':
- __first = __parse_bracket_expression(__first, __last);
- break;
- case '(': {
- ++__first;
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_paren>();
- _ForwardIterator __temp = std::next(__first);
- if (__temp != __last && *__first == '?' && *__temp == ':') {
- ++__open_count_;
- __first = __parse_ecma_exp(++__temp, __last);
- if (__first == __last || *__first != ')')
- std::__throw_regex_error<regex_constants::error_paren>();
- --__open_count_;
- ++__first;
- } else {
- __push_begin_marked_subexpression();
- unsigned __temp_count = __marked_count_;
- ++__open_count_;
- __first = __parse_ecma_exp(__first, __last);
- if (__first == __last || *__first != ')')
- std::__throw_regex_error<regex_constants::error_paren>();
- __push_end_marked_subexpression(__temp_count);
- --__open_count_;
- ++__first;
- }
- } break;
- case '*':
- case '+':
- case '?':
- case '{':
- std::__throw_regex_error<regex_constants::error_badrepeat>();
- break;
- default:
- __first = __parse_pattern_character(__first, __last);
- break;
- }
- }
- return __first;
-}
+ template <class _Bp, class _Ap, class _Cp, class _Tp>
+ friend bool
+ regex_search(_Bp, _Bp, match_results<_Bp, _Ap>&, const basic_regex<_Cp, _Tp>&, regex_constants::match_flag_type);
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_atom_escape(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last && *__first == '\\') {
- _ForwardIterator __t1 = std::next(__first);
- if (__t1 == __last)
- std::__throw_regex_error<regex_constants::error_escape>();
-
- _ForwardIterator __t2 = __parse_decimal_escape(__t1, __last);
- if (__t2 != __t1)
- __first = __t2;
- else {
- __t2 = __parse_character_class_escape(__t1, __last);
- if (__t2 != __t1)
- __first = __t2;
- else {
- __t2 = __parse_character_escape(__t1, __last);
- if (__t2 != __t1)
- __first = __t2;
- }
- }
- }
- return __first;
-}
+ template <class _Ap, class _Cp, class _Tp>
+ friend bool
+ regex_search(const _Cp*,
+ const _Cp*,
+ match_results<const _Cp*, _Ap>&,
+ const basic_regex<_Cp, _Tp>&,
+ regex_constants::match_flag_type);
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_decimal_escape(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- if (*__first == '0') {
- __push_char(_CharT());
- ++__first;
- } else if ('1' <= *__first && *__first <= '9') {
- unsigned __v = *__first - '0';
- for (++__first; __first != __last && '0' <= *__first && *__first <= '9'; ++__first) {
- if (__v >= numeric_limits<unsigned>::max() / 10)
- std::__throw_regex_error<regex_constants::error_backref>();
- __v = 10 * __v + *__first - '0';
- }
- if (__v == 0 || __v > mark_count())
- std::__throw_regex_error<regex_constants::error_backref>();
- __push_back_ref(__v);
- }
- }
- return __first;
-}
+ template <class _Bp, class _Cp, class _Tp>
+ friend bool regex_search(_Bp, _Bp, const basic_regex<_Cp, _Tp>&, regex_constants::match_flag_type);
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_character_class_escape(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- __bracket_expression<_CharT, _Traits>* __ml;
- switch (*__first) {
- case 'd':
- __ml = __start_matching_list(false);
- __ml->__add_class(ctype_base::digit);
- ++__first;
- break;
- case 'D':
- __ml = __start_matching_list(true);
- __ml->__add_class(ctype_base::digit);
- ++__first;
- break;
- case 's':
- __ml = __start_matching_list(false);
- __ml->__add_class(ctype_base::space);
- ++__first;
- break;
- case 'S':
- __ml = __start_matching_list(true);
- __ml->__add_class(ctype_base::space);
- ++__first;
- break;
- case 'w':
- __ml = __start_matching_list(false);
- __ml->__add_class(ctype_base::alnum);
- __ml->__add_char('_');
- ++__first;
- break;
- case 'W':
- __ml = __start_matching_list(true);
- __ml->__add_class(ctype_base::alnum);
- __ml->__add_char('_');
- ++__first;
- break;
- }
- }
- return __first;
-}
+ template <class _Cp, class _Tp>
+ friend bool regex_search(const _Cp*, const _Cp*, const basic_regex<_Cp, _Tp>&, regex_constants::match_flag_type);
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator basic_regex<_CharT, _Traits>::__parse_character_escape(
- _ForwardIterator __first, _ForwardIterator __last, basic_string<_CharT>* __str) {
- if (__first != __last) {
- _ForwardIterator __t;
- unsigned __sum = 0;
- int __hd;
- switch (*__first) {
- case 'f':
- if (__str)
- *__str = _CharT(0xC);
- else
- __push_char(_CharT(0xC));
- ++__first;
- break;
- case 'n':
- if (__str)
- *__str = _CharT(0xA);
- else
- __push_char(_CharT(0xA));
- ++__first;
- break;
- case 'r':
- if (__str)
- *__str = _CharT(0xD);
- else
- __push_char(_CharT(0xD));
- ++__first;
- break;
- case 't':
- if (__str)
- *__str = _CharT(0x9);
- else
- __push_char(_CharT(0x9));
- ++__first;
- break;
- case 'v':
- if (__str)
- *__str = _CharT(0xB);
- else
- __push_char(_CharT(0xB));
- ++__first;
- break;
- case 'c':
- if ((__t = std::next(__first)) != __last) {
- if (('A' <= *__t && *__t <= 'Z') || ('a' <= *__t && *__t <= 'z')) {
- if (__str)
- *__str = _CharT(*__t % 32);
- else
- __push_char(_CharT(*__t % 32));
- __first = ++__t;
- } else
- std::__throw_regex_error<regex_constants::error_escape>();
- } else
- std::__throw_regex_error<regex_constants::error_escape>();
- break;
- case 'u':
- ++__first;
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_escape>();
- __hd = __traits_.value(*__first, 16);
- if (__hd == -1)
- std::__throw_regex_error<regex_constants::error_escape>();
- __sum = 16 * __sum + static_cast<unsigned>(__hd);
- ++__first;
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_escape>();
- __hd = __traits_.value(*__first, 16);
- if (__hd == -1)
- std::__throw_regex_error<regex_constants::error_escape>();
- __sum = 16 * __sum + static_cast<unsigned>(__hd);
- [[__fallthrough__]];
- case 'x':
- ++__first;
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_escape>();
- __hd = __traits_.value(*__first, 16);
- if (__hd == -1)
- std::__throw_regex_error<regex_constants::error_escape>();
- __sum = 16 * __sum + static_cast<unsigned>(__hd);
- ++__first;
- if (__first == __last)
- std::__throw_regex_error<regex_constants::error_escape>();
- __hd = __traits_.value(*__first, 16);
- if (__hd == -1)
- std::__throw_regex_error<regex_constants::error_escape>();
- __sum = 16 * __sum + static_cast<unsigned>(__hd);
- if (__str)
- *__str = _CharT(__sum);
- else
- __push_char(_CharT(__sum));
- ++__first;
- break;
- case '0':
- if (__str)
- *__str = _CharT(0);
- else
- __push_char(_CharT(0));
- ++__first;
- break;
- default:
- if (!__traits_.isctype(*__first, ctype_base::alnum)) {
- if (__str)
- *__str = *__first;
- else
- __push_char(*__first);
- ++__first;
- } else
- std::__throw_regex_error<regex_constants::error_escape>();
- break;
- }
- }
- return __first;
-}
+ template <class _Cp, class _Ap, class _Tp>
+ friend bool regex_search(
+ const _Cp*, match_results<const _Cp*, _Ap>&, const basic_regex<_Cp, _Tp>&, regex_constants::match_flag_type);
-template <class _CharT, class _Traits>
-template <class _ForwardIterator>
-_ForwardIterator
-basic_regex<_CharT, _Traits>::__parse_pattern_character(_ForwardIterator __first, _ForwardIterator __last) {
- if (__first != __last) {
- switch (*__first) {
- case '^':
- case '$':
- case '\\':
- case '.':
- case '*':
- case '+':
- case '?':
- case '(':
- case ')':
- case '[':
- case ']':
- case '{':
- case '}':
- case '|':
- break;
- default:
- __push_char(*__first);
- ++__first;
- break;
- }
- }
- return __first;
-}
+ template <class _ST, class _SA, class _Cp, class _Tp>
+ friend bool regex_search(const basic_string<_Cp, _ST, _SA>& __s,
+ const basic_regex<_Cp, _Tp>& __e,
+ regex_constants::match_flag_type __flags);
-template <class _CharT, class _Traits>
-bool basic_regex<_CharT, _Traits>::__test_back_ref(_CharT __c) {
- unsigned __val = __traits_.value(__c, 10);
- if (__val >= 1 && __val <= 9) {
- if (__val > mark_count())
- std::__throw_regex_error<regex_constants::error_backref>();
- __push_back_ref(__val);
- return true;
- }
+ template <class _ST, class _SA, class _Ap, class _Cp, class _Tp>
+ friend bool regex_search(const basic_string<_Cp, _ST, _SA>& __s,
+ match_results<typename basic_string<_Cp, _ST, _SA>::const_iterator, _Ap>&,
+ const basic_regex<_Cp, _Tp>& __e,
+ regex_constants::match_flag_type __flags);
- return false;
-}
+ template <class _Iter, class _Ap, class _Cp, class _Tp>
+ friend bool
+ regex_search(__wrap_iter<_Iter> __first,
+ __wrap_iter<_Iter> __last,
+ match_results<__wrap_iter<_Iter>, _Ap>& __m,
+ const basic_regex<_Cp, _Tp>& __e,
+ regex_constants::match_flag_type __flags);
+};
-template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_loop(
- size_t __min, size_t __max, __owns_one_state<_CharT>* __s, size_t __mexp_begin, size_t __mexp_end, bool __greedy) {
- unique_ptr<__empty_state<_CharT> > __e1(new __empty_state<_CharT>(__end_->first()));
- __end_->first() = nullptr;
- unique_ptr<__loop<_CharT> > __e2(
- new __loop<_CharT>(__loop_count_, __s->first(), __e1.get(), __mexp_begin, __mexp_end, __greedy, __min, __max));
- __s->first() = nullptr;
- __e1.release();
- __end_->first() = new __repeat_one_loop<_CharT>(__e2.get());
- __end_ = __e2->second();
- __s->first() = __e2.release();
- ++__loop_count_;
-}
+# if _LIBCPP_STD_VER >= 17
+template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0>
+basic_regex(_ForwardIterator, _ForwardIterator, regex_constants::syntax_option_type = regex_constants::ECMAScript)
+ -> basic_regex<typename iterator_traits<_ForwardIterator>::value_type>;
+# endif
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_char(value_type __c) {
- if (flags() & icase)
- __end_->first() = new __match_char_icase<_CharT, _Traits>(__traits_, __c, __end_->first());
- else if (flags() & collate)
- __end_->first() = new __match_char_collate<_CharT, _Traits>(__traits_, __c, __end_->first());
- else
- __end_->first() = new __match_char<_CharT>(__c, __end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
-}
-
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::icase;
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_begin_marked_subexpression() {
- if (!(__flags_ & nosubs)) {
- __end_->first() = new __begin_marked_subexpression<_CharT>(++__marked_count_, __end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
- }
-}
-
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::nosubs;
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_end_marked_subexpression(unsigned __sub) {
- if (!(__flags_ & nosubs)) {
- __end_->first() = new __end_marked_subexpression<_CharT>(__sub, __end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
- }
-}
-
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::optimize;
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_l_anchor() {
- __end_->first() = new __l_anchor_multiline<_CharT>(__use_multiline(), __end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
-}
-
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::collate;
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_r_anchor() {
- __end_->first() = new __r_anchor_multiline<_CharT>(__use_multiline(), __end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
-}
-
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::ECMAScript;
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_match_any() {
- __end_->first() = new __match_any<_CharT>(__end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
-}
-
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::basic;
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_match_any_but_newline() {
- __end_->first() = new __match_any_but_newline<_CharT>(__end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
-}
-
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::extended;
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_empty() {
- __end_->first() = new __empty_state<_CharT>(__end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
-}
-
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::awk;
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_word_boundary(bool __invert) {
- __end_->first() = new __word_boundary<_CharT, _Traits>(__traits_, __invert, __end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
-}
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::grep;
+template <class _CharT, class _Traits>
+const regex_constants::syntax_option_type basic_regex<_CharT, _Traits>::egrep;
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_back_ref(int __i) {
- if (flags() & icase)
- __end_->first() = new __back_ref_icase<_CharT, _Traits>(__traits_, __i, __end_->first());
- else if (flags() & collate)
- __end_->first() = new __back_ref_collate<_CharT, _Traits>(__traits_, __i, __end_->first());
- else
- __end_->first() = new __back_ref<_CharT>(__i, __end_->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
+void basic_regex<_CharT, _Traits>::swap(basic_regex& __r) {
+ using std::swap;
+ swap(__traits_, __r.__traits_);
+ swap(__flags_, __r.__flags_);
+ swap(__marked_count_, __r.__marked_count_);
+ swap(__loop_count_, __r.__loop_count_);
+ swap(__open_count_, __r.__open_count_);
+ swap(__start_, __r.__start_);
+ swap(__end_, __r.__end_);
}
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_alternation(__owns_one_state<_CharT>* __sa, __owns_one_state<_CharT>* __ea) {
- __sa->first() = new __alternate<_CharT>(
- static_cast<__owns_one_state<_CharT>*>(__sa->first()), static_cast<__owns_one_state<_CharT>*>(__ea->first()));
- __ea->first() = nullptr;
- __ea->first() = new __empty_state<_CharT>(__end_->first());
- __end_->first() = nullptr;
- __end_->first() = new __empty_non_own_state<_CharT>(__ea->first());
- __end_ = static_cast<__owns_one_state<_CharT>*>(__ea->first());
+inline _LIBCPP_HIDE_FROM_ABI void swap(basic_regex<_CharT, _Traits>& __x, basic_regex<_CharT, _Traits>& __y) {
+ return __x.swap(__y);
}
template <class _CharT, class _Traits>
-__bracket_expression<_CharT, _Traits>* basic_regex<_CharT, _Traits>::__start_matching_list(bool __negate) {
- __bracket_expression<_CharT, _Traits>* __r = new __bracket_expression<_CharT, _Traits>(
- __traits_, __end_->first(), __negate, __flags_ & icase, __flags_ & collate);
- __end_->first() = __r;
- __end_ = __r;
- return __r;
+template <class _ForwardIterator>
+void basic_regex<_CharT, _Traits>::__init(_ForwardIterator __first, _ForwardIterator __last) {
+ if (__get_grammar(__flags_) == 0)
+ __flags_ |= regex_constants::ECMAScript;
+ _ForwardIterator __temp = __parse(__first, __last);
+ if (__temp != __last)
+ std::__throw_regex_error<regex_constants::__re_err_parse>();
}
template <class _CharT, class _Traits>
-void basic_regex<_CharT, _Traits>::__push_lookahead(const basic_regex& __exp, bool __invert, unsigned __mexp) {
- __end_->first() = new __lookahead<_CharT, _Traits>(__exp, __invert, __end_->first(), __mexp);
- __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
+template <class _ForwardIterator>
+_ForwardIterator basic_regex<_CharT, _Traits>::__parse(_ForwardIterator __first, _ForwardIterator __last) {
+ switch (__get_grammar(__flags_)) {
+ case ECMAScript: {
+ __regex::__ecma::__parser<_CharT, _Traits, _ForwardIterator> __parser(__first, __last, __traits_, flags());
+ __parser.__parse_ecma();
+ __start_.reset(new __interpreter_state<_CharT, _Traits>(__parser.__extract_interpreter(), nullptr));
+ __end_ = __start_.get();
+ __marked_count_ = __parser.mark_count();
+ return __last;
+ }
+ case basic:
+ case grep: {
+ __regex::__basic::__parser<_CharT, _Traits, _ForwardIterator> __parser(__first, __last, __traits_, flags());
+ if (__get_grammar(__flags_) == basic)
+ __parser.__parse_basic();
+ else
+ __parser.__parse_grep();
+ __start_.reset(new __interpreter_state<_CharT, _Traits>(__parser.__extract_interpreter(), nullptr));
+ __end_ = __start_.get();
+ __marked_count_ = __parser.mark_count();
+ return __last;
+ }
+ case awk:
+ case extended:
+ case egrep: {
+ __regex::__extended::__parser<_CharT, _Traits, _ForwardIterator> __parser(__first, __last, __traits_, flags());
+ if (auto __grammar = __get_grammar(__flags_); __grammar == extended || __grammar == awk)
+ __parser.__parse_extended();
+ else
+ __parser.__parse_egrep();
+ __start_.reset(new __interpreter_state<_CharT, _Traits>(__parser.__extract_interpreter(), nullptr));
+ __end_ = __start_.get();
+ __marked_count_ = __parser.mark_count();
+ return __last;
+ }
+ default:
+ std::__throw_regex_error<regex_constants::__re_err_grammar>();
+ }
+ return __first;
}
// sub_match
@@ -4072,9 +2156,6 @@ private:
template <class _Bp, class _Ap>
friend bool operator==(const match_results<_Bp, _Ap>&, const match_results<_Bp, _Ap>&);
- template <class, class>
- friend class __lookahead;
-
template <class, class, class>
friend class regex_iterator;
};
@@ -4463,7 +2544,31 @@ bool basic_regex<_CharT, _Traits>::__match_at_start(
const _CharT* __last,
match_results<const _CharT*, _Allocator>& __m,
regex_constants::match_flag_type __flags,
- bool __at_first) const {
+ bool __at_first,
+ __interpreter_state<_CharT, _Traits>* __interp) const {
+ if (__interp) {
+ sub_match<const _CharT*> __unmatched;
+ __unmatched.first = __last;
+ __unmatched.second = __last;
+ __unmatched.matched = false;
+
+ std::__state<_CharT> __s;
+ __s.__first_ = __first;
+ __s.__last_ = __last;
+ __s.__current_ = __first;
+ __s.__sub_matches_.resize(mark_count(), __unmatched);
+ __s.__flags_ = __flags;
+ __s.__at_first_ = __at_first;
+ __interp->__exec(__s);
+ if (__s.__do_ != __state::__end_state)
+ return false;
+ __m.__matches_[0].first = __first;
+ __m.__matches_[0].second = std::next(__first, __s.__current_ - __first);
+ __m.__matches_[0].matched = true;
+ for (unsigned __i = 0; __i < __s.__sub_matches_.size(); ++__i)
+ __m.__matches_[__i + 1] = __s.__sub_matches_[__i];
+ return true;
+ }
if (__get_grammar(__flags_) == ECMAScript)
return __match_at_start_ecma(__states, __first, __last, __m, __flags, __at_first);
if (mark_count() == 0)
@@ -4481,9 +2586,12 @@ bool basic_regex<_CharT, _Traits>::__search(
if (__flags & regex_constants::match_prev_avail)
__flags &= ~(regex_constants::match_not_bol | regex_constants::match_not_bow);
+ auto* __interp = dynamic_cast<__interpreter_state<_CharT, _Traits>*>(__start_.get());
+
vector<__state> __states_buffer;
__m.__init(1 + mark_count(), __first, __last, __flags & regex_constants::__no_update_pos);
- if (__match_at_start(__states_buffer, __first, __last, __m, __flags, !(__flags & regex_constants::__no_update_pos))) {
+ if (__match_at_start(
+ __states_buffer, __first, __last, __m, __flags, !(__flags & regex_constants::__no_update_pos), __interp)) {
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
__m.__suffix_.first = __m[0].second;
@@ -4494,7 +2602,7 @@ bool basic_regex<_CharT, _Traits>::__search(
__flags |= regex_constants::match_prev_avail;
for (++__first; __first != __last; ++__first) {
__m.__matches_.assign(__m.size(), __m.__unmatched_);
- if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false)) {
+ if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false, __interp)) {
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
__m.__suffix_.first = __m[0].second;
@@ -4504,7 +2612,7 @@ bool basic_regex<_CharT, _Traits>::__search(
__m.__matches_.assign(__m.size(), __m.__unmatched_);
}
__m.__matches_.assign(__m.size(), __m.__unmatched_);
- if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false)) {
+ if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false, __interp)) {
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
__m.__suffix_.first = __m[0].second;
diff --git a/libcxx/src/regex.cpp b/libcxx/src/regex.cpp
index 9d7d1699ae266..1e5bc9cdb83db 100644
--- a/libcxx/src/regex.cpp
+++ b/libcxx/src/regex.cpp
@@ -353,8 +353,16 @@ regex_traits<char>::char_class_type __get_classname(const char* s, bool __icase)
return r;
}
+template <class _CharT>
+class __match_any_but_newline : public __owns_one_state<_CharT> {
+public:
+ typedef std::__state<_CharT> __state;
+
+ void __exec(__state&) const override;
+};
+
template <>
-void __match_any_but_newline<char>::__exec(__state& __s) const {
+_LIBCPP_EXPORTED_FROM_ABI void __match_any_but_newline<char>::__exec(__state& __s) const {
if (__s.__current_ != __s.__last_) {
switch (*__s.__current_) {
case '\r':
@@ -374,8 +382,9 @@ void __match_any_but_newline<char>::__exec(__state& __s) const {
}
}
+#if _LIBCPP_HAS_WIDE_CHARACTERS
template <>
-void __match_any_but_newline<wchar_t>::__exec(__state& __s) const {
+_LIBCPP_EXPORTED_FROM_ABI void __match_any_but_newline<wchar_t>::__exec(__state& __s) const {
if (__s.__current_ != __s.__last_) {
switch (*__s.__current_) {
case '\r':
@@ -396,6 +405,7 @@ void __match_any_but_newline<wchar_t>::__exec(__state& __s) const {
__s.__node_ = nullptr;
}
}
+#endif
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/re/re.alg/re.alg.search/basic.pass.cpp b/libcxx/test/std/re/re.alg/re.alg.search/basic.pass.cpp
index 80918d2b2958a..4006b47896509 100644
--- a/libcxx/test/std/re/re.alg/re.alg.search/basic.pass.cpp
+++ b/libcxx/test/std/re/re.alg/re.alg.search/basic.pass.cpp
@@ -37,7 +37,7 @@ int main(int, char**)
}
{
std::cmatch m;
- assert(!std::regex_search("a", m, std::regex("[a-[.hyphen.]]", std::regex_constants::basic)));
+ assert(!std::regex_search("a", m, std::regex("[[.hyphen.]-0]", std::regex_constants::basic)));
assert(m.size() == 0);
assert(m.empty());
}
>From 2c699ee91d993faa547e1993f15f51d180468871 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sat, 28 Mar 2026 04:59:31 +0100
Subject: [PATCH 05/21] [libc++] Add a more efficient interface to call the new
regex implementation
---
libcxx/include/__regex/interpreter.h | 79 +++++++++++++++++++++++++---
libcxx/include/regex | 79 ++++++++++++++++------------
2 files changed, 115 insertions(+), 43 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index fc7aefa7db8a4..864b645c56d3e 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -125,6 +125,27 @@ struct __bracket_expr {
typename _Traits::char_class_type __neg_mask_ = 0;
};
+// This is essentially an optional<vector<sub_match<const _CharT*>>>, just back-ported to C++03
+// FIXME: This isn't exactly the optimal representation
+template <class _CharT>
+struct __search_result {
+ union {
+ struct {
+ const _CharT* __match_first_;
+ const _CharT* __match_last_;
+ vector<sub_match<const _CharT*>> __sub_matches_;
+ };
+ };
+ bool __matched_;
+
+ __search_result() : __matched_(false) {}
+ __search_result(const _CharT* __first, const _CharT* __last, vector<sub_match<const _CharT*>> __sub_matches)
+ : __match_first_(__first), __match_last_(__last), __sub_matches_(std::move(__sub_matches)), __matched_(true) {}
+ __search_result(const __search_result&) = delete;
+ __search_result& operator=(const __search_result&) = delete;
+ ~__search_result() {}
+};
+
template <class _CharT, class _Traits>
class __interpreter {
vector<__interpreter_info<_CharT> > __machine_;
@@ -777,15 +798,19 @@ class __interpreter {
const _CharT* __last,
vector<sub_match<const _CharT*>>& __sub_matches) const {
using __local_state = typename __global_execution_state::__local_execution_state;
- __local_state __base_state;
- __base_state.__sub_matches_ = std::move(__sub_matches);
- __base_state.__current_ = __first;
- if (!__initial_loop_values_.empty()) {
- __base_state.__loop_values_ = std::make_unique_for_overwrite<size_t[]>(__initial_loop_values_.size());
+
+ __local_state __base_state{
+ .__current_ = __first,
+ .__sub_matches_ = std::move(__sub_matches),
+ .__current_pos_ = 0,
+ .__loop_values_ = __initial_loop_values_.empty()
+ ? nullptr
+ : std::make_unique_for_overwrite<size_t[]>(__initial_loop_values_.size()),
+ .__loop_starts_ =
+ __initial_loop_values_.empty() ? nullptr : std::make_unique<const _CharT*[]>(__initial_loop_values_.size()),
+ };
+ if (!__initial_loop_values_.empty())
std::copy(__initial_loop_values_.begin(), __initial_loop_values_.end(), __base_state.__loop_values_.get());
- __base_state.__loop_starts_ = std::make_unique<const _CharT*[]>(__initial_loop_values_.size());
- }
- __base_state.__current_pos_ = 0;
__global_execution_state __gexec_state{{}, *this, __flags};
auto [__base_state_matched, __gcounter] = __base_state.__execute(__first, __last, __gexec_state);
@@ -836,6 +861,44 @@ class __interpreter {
}
}
+ __search_result<_CharT> __execute_search(
+ const _CharT* __first, const _CharT* __last, regex_constants::match_flag_type __flags, size_t __marked_count) {
+ sub_match<const _CharT*> __unmatched;
+ __unmatched.first = __last;
+ __unmatched.second = __last;
+ __unmatched.matched = false;
+
+ vector<sub_match<const _CharT*>> __sub_matches(__marked_count, __unmatched);
+ if (auto [__success, __last_val] = __execute(
+ __flags | ((__flags & regex_constants::__no_update_pos) ? regex_constants::match_flag_type()
+ : regex_constants::__at_first),
+ __first,
+ __last,
+ __sub_matches);
+ __success) {
+ return {__first, __last_val, std::move(__sub_matches)};
+ }
+
+ if (__first == __last || (__flags & regex_constants::match_continuous))
+ return {};
+
+ __flags |= regex_constants::match_prev_avail;
+
+ for (++__first; __first != __last; ++__first) {
+ __sub_matches.assign(__marked_count, __unmatched);
+ if (auto [__success, __last_val] = __execute(__flags, __first, __last, __sub_matches); __success) {
+ return {__first, __last_val, std::move(__sub_matches)};
+ }
+ }
+
+ __sub_matches.assign(__marked_count, __unmatched);
+ if (auto [__success, __last_val] = __execute(__flags, __first, __last, __sub_matches); __success) {
+ return {__first, __last_val, std::move(__sub_matches)};
+ }
+
+ return {};
+ }
+
const _Traits& __get_traits() const { return __traits_; }
};
} // namespace __regex
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 654f02a5df4f4..c0011c954cc26 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -1270,13 +1270,22 @@ void __empty_state<_CharT>::__exec(__state& __s) const {
__s.__node_ = this->first();
}
+template <class _CharT>
+class __regex_search_state : public __empty_state<_CharT> {
+public:
+ explicit __regex_search_state(__node<_CharT>* __s) : __empty_state<_CharT>(__s) {}
+
+ virtual __regex::__search_result<_CharT> __exec_regex_search(
+ const _CharT* __first, const _CharT* __last, regex_constants::match_flag_type, size_t __marked_count) = 0;
+};
+
template <class _CharT, class _Traits>
-class __interpreter_state : public __empty_state<_CharT> {
+class __interpreter_state : public __regex_search_state<_CharT> {
__regex::__interpreter<_CharT, _Traits> __machine_;
public:
_LIBCPP_HIDE_FROM_ABI __interpreter_state(__regex::__interpreter<_CharT, _Traits> __machine, __node<_CharT>* __s)
- : __empty_state<_CharT>(__s), __machine_(std::move(__machine)) {}
+ : __regex_search_state<_CharT>(__s), __machine_(std::move(__machine)) {}
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __exec(__state<_CharT>& __state) const override {
auto __res = __machine_.__execute(
@@ -1287,6 +1296,14 @@ public:
__state.__do_ = __res.first ? std::__state<_CharT>::__end_state : std::__state<_CharT>::__reject;
__state.__current_ = __res.second;
}
+
+ __regex::__search_result<_CharT> __exec_regex_search(
+ const _CharT* __first,
+ const _CharT* __last,
+ regex_constants::match_flag_type __flags,
+ size_t __marked_count) override {
+ return __machine_.__execute_search(__first, __last, __flags, __marked_count);
+ }
};
template <class _CharT, class _Traits = regex_traits<_CharT> >
@@ -1471,8 +1488,7 @@ private:
const _CharT* __last,
match_results<const _CharT*, _Allocator>& __m,
regex_constants::match_flag_type __flags,
- bool,
- __interpreter_state<_CharT, _Traits>*) const;
+ bool) const;
template <class _Allocator>
bool __match_at_start_ecma(
vector<__state>& __states,
@@ -2544,31 +2560,7 @@ bool basic_regex<_CharT, _Traits>::__match_at_start(
const _CharT* __last,
match_results<const _CharT*, _Allocator>& __m,
regex_constants::match_flag_type __flags,
- bool __at_first,
- __interpreter_state<_CharT, _Traits>* __interp) const {
- if (__interp) {
- sub_match<const _CharT*> __unmatched;
- __unmatched.first = __last;
- __unmatched.second = __last;
- __unmatched.matched = false;
-
- std::__state<_CharT> __s;
- __s.__first_ = __first;
- __s.__last_ = __last;
- __s.__current_ = __first;
- __s.__sub_matches_.resize(mark_count(), __unmatched);
- __s.__flags_ = __flags;
- __s.__at_first_ = __at_first;
- __interp->__exec(__s);
- if (__s.__do_ != __state::__end_state)
- return false;
- __m.__matches_[0].first = __first;
- __m.__matches_[0].second = std::next(__first, __s.__current_ - __first);
- __m.__matches_[0].matched = true;
- for (unsigned __i = 0; __i < __s.__sub_matches_.size(); ++__i)
- __m.__matches_[__i + 1] = __s.__sub_matches_[__i];
- return true;
- }
+ bool __at_first) const {
if (__get_grammar(__flags_) == ECMAScript)
return __match_at_start_ecma(__states, __first, __last, __m, __flags, __at_first);
if (mark_count() == 0)
@@ -2586,12 +2578,29 @@ bool basic_regex<_CharT, _Traits>::__search(
if (__flags & regex_constants::match_prev_avail)
__flags &= ~(regex_constants::match_not_bol | regex_constants::match_not_bow);
- auto* __interp = dynamic_cast<__interpreter_state<_CharT, _Traits>*>(__start_.get());
+ __m.__init(1 + mark_count(), __first, __last, __flags & regex_constants::__no_update_pos);
+
+ if (auto* __interp = dynamic_cast<__regex_search_state<_CharT>*>(__start_.get())) {
+ auto __res = __interp->__exec_regex_search(__first, __last, __flags, mark_count());
+ if (!__res.__matched_) {
+ __m.__matches_.clear();
+ return false;
+ }
+ vector<sub_match<const _CharT*>> __sub_matches(std::move(__res.__sub_matches_));
+ std::__destroy_at(&__res.__sub_matches_);
+ __m.__matches_[0].first = __res.__match_first_;
+ __m.__matches_[0].second = __res.__match_last_;
+ __m.__matches_[0].matched = true;
+ std::copy(__sub_matches.begin(), __sub_matches.end(), __m.__matches_.begin() + 1);
+ __m.__prefix_.second = __m[0].first;
+ __m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
+ __m.__suffix_.first = __m[0].second;
+ __m.__suffix_.matched = __m.__suffix_.first != __m.__suffix_.second;
+ return true;
+ }
vector<__state> __states_buffer;
- __m.__init(1 + mark_count(), __first, __last, __flags & regex_constants::__no_update_pos);
- if (__match_at_start(
- __states_buffer, __first, __last, __m, __flags, !(__flags & regex_constants::__no_update_pos), __interp)) {
+ if (__match_at_start(__states_buffer, __first, __last, __m, __flags, !(__flags & regex_constants::__no_update_pos))) {
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
__m.__suffix_.first = __m[0].second;
@@ -2602,7 +2611,7 @@ bool basic_regex<_CharT, _Traits>::__search(
__flags |= regex_constants::match_prev_avail;
for (++__first; __first != __last; ++__first) {
__m.__matches_.assign(__m.size(), __m.__unmatched_);
- if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false, __interp)) {
+ if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false)) {
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
__m.__suffix_.first = __m[0].second;
@@ -2612,7 +2621,7 @@ bool basic_regex<_CharT, _Traits>::__search(
__m.__matches_.assign(__m.size(), __m.__unmatched_);
}
__m.__matches_.assign(__m.size(), __m.__unmatched_);
- if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false, __interp)) {
+ if (__match_at_start(__states_buffer, __first, __last, __m, __flags, false)) {
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
__m.__suffix_.first = __m[0].second;
>From 087d4afa4666dd2500f455863b98d9146e47c47d Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 29 Mar 2026 03:27:31 +0200
Subject: [PATCH 06/21] [libc++] Move the execution states out of __interpreter
---
libcxx/include/__regex/interpreter.h | 852 ++++++++++++++-------------
1 file changed, 429 insertions(+), 423 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 864b645c56d3e..5a52d5bb26eeb 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -147,11 +147,17 @@ struct __search_result {
};
template <class _CharT, class _Traits>
-class __interpreter {
- vector<__interpreter_info<_CharT> > __machine_;
- vector<size_t> __initial_loop_values_;
- _Traits __traits_;
- bool __find_longest_;
+struct __global_execution_state;
+
+template <class _CharT, class _Traits>
+struct __local_execution_state {
+ using __global_state = __global_execution_state<_CharT, _Traits>;
+
+ const _CharT* __current_;
+ vector<sub_match<const _CharT*> > __sub_matches_;
+ size_t __current_pos_;
+ unique_ptr<size_t[]> __loop_values_;
+ unique_ptr<const _CharT*[]> __loop_starts_;
static pair<size_t, size_t>
__read_uleb_impl(_LIBCPP_NOESCAPE const __interpreter_info<_CharT>* __machine, size_t __current_pos) {
@@ -177,467 +183,467 @@ class __interpreter {
return __val;
}
- struct __global_execution_state {
- struct __local_execution_state;
-
- vector<__local_execution_state> __states_;
- const __interpreter& __machine_;
- regex_constants::match_flag_type __flags_;
-
- struct __local_execution_state {
- const _CharT* __current_;
- vector<sub_match<const _CharT*> > __sub_matches_;
- size_t __current_pos_;
- unique_ptr<size_t[]> __loop_values_;
- unique_ptr<const _CharT*[]> __loop_starts_;
-
- void __copy_to(const _CharT* const __current,
- vector<__local_execution_state>& __vec,
- __global_execution_state& __gstate) {
- auto __loop_value_count = __gstate.__machine_.__initial_loop_values_.size();
- auto __loop_values_copy = std::make_unique_for_overwrite<size_t[]>(__loop_value_count);
- std::copy_n(__loop_values_.get(), __loop_value_count, __loop_values_copy.get());
- auto __loop_starts_copy = std::make_unique_for_overwrite<const _CharT*[]>(__loop_value_count);
- std::copy_n(__loop_starts_.get(), __loop_value_count, __loop_starts_copy.get());
- __vec.emplace_back(
- __current, __sub_matches_, __current_pos_, std::move(__loop_values_copy), std::move(__loop_starts_copy));
- }
+ void __copy_to(const _CharT* const __current, vector<__local_execution_state>& __vec, __global_state& __gstate) {
+ auto __loop_value_count = __gstate.__machine_.__initial_loop_values_.size();
+ auto __loop_values_copy = std::make_unique_for_overwrite<size_t[]>(__loop_value_count);
+ std::copy_n(__loop_values_.get(), __loop_value_count, __loop_values_copy.get());
+ auto __loop_starts_copy = std::make_unique_for_overwrite<const _CharT*[]>(__loop_value_count);
+ std::copy_n(__loop_starts_.get(), __loop_value_count, __loop_starts_copy.get());
+ __vec.emplace_back(
+ __current, __sub_matches_, __current_pos_, std::move(__loop_values_copy), std::move(__loop_starts_copy));
+ }
- static bool __is_word_boundary(const _CharT* __first,
- const _CharT* __last,
- const _CharT* const __current,
- __global_execution_state& __gstate) {
- auto __is_word_char = [&](char __c) {
- return __c == '_' || __gstate.__machine_.__traits_.isctype(__c, ctype_base::alnum);
- };
+ static bool __is_word_boundary(
+ const _CharT* __first, const _CharT* __last, const _CharT* const __current, __global_state& __gstate) {
+ auto __is_word_char = [&](char __c) {
+ return __c == '_' || __gstate.__machine_.__traits_.isctype(__c, ctype_base::alnum);
+ };
- if (__first == __last)
- return false;
+ if (__first == __last)
+ return false;
- if (__current == __last) {
- return !(__gstate.__flags_ & regex_constants::match_not_eow) && __is_word_char(__current[-1]);
- }
+ if (__current == __last) {
+ return !(__gstate.__flags_ & regex_constants::match_not_eow) && __is_word_char(__current[-1]);
+ }
- if (__current == __first && !(__gstate.__flags_ & regex_constants::match_prev_avail)) {
- return !(__gstate.__flags_ & regex_constants::match_not_bow) && __is_word_char(__current[0]);
- }
+ if (__current == __first && !(__gstate.__flags_ & regex_constants::match_prev_avail)) {
+ return !(__gstate.__flags_ & regex_constants::match_not_bow) && __is_word_char(__current[0]);
+ }
+
+ return __is_word_char(__current[-1]) != __is_word_char(__current[0]);
+ }
+
+ struct __charlist_result {
+ bool __matched;
+ bool __matched_digraph;
+ size_t __new_pos;
+ };
- return __is_word_char(__current[-1]) != __is_word_char(__current[0]);
+ static __charlist_result __exec_match_character_list(
+ const __interpreter_info<_CharT>* const __code,
+ const _CharT* const __last,
+ const _CharT* const __current,
+ const __global_state& __gstate,
+ size_t __current_pos) {
+ static constexpr auto __buffer_size =
+ std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1));
+ _CharT __buffer[__buffer_size];
+ for (size_t __i = 0; __i != __buffer_size; ++__i)
+ __buffer[__i] = __code[__current_pos++].__char_;
+ typename _Traits::char_class_type __mask;
+ __builtin_memcpy(&__mask, __buffer, sizeof(typename _Traits::char_class_type));
+
+ for (size_t __i = 0; __i != __buffer_size; ++__i)
+ __buffer[__i] = __code[__current_pos++].__char_;
+ typename _Traits::char_class_type __neg_mask;
+ __builtin_memcpy(&__neg_mask, __buffer, sizeof(typename _Traits::char_class_type));
+
+ auto __chars = __read_uleb(__code, __current_pos);
+ auto __digraphs = __read_uleb(__code, __current_pos) * 2;
+ auto __ranges = __read_uleb(__code, __current_pos) * 4;
+ auto __neg_chars = __read_uleb(__code, __current_pos);
+ auto __equiv_count = __read_uleb(__code, __current_pos);
+ auto __equiv_size = __read_uleb(__code, __current_pos);
+
+ bool __found = false;
+
+ for (size_t __i = 0; __i != __chars; ++__i) {
+ if (__code[__current_pos + __i].__char_ == *__current) {
+ __found = true;
+ break;
}
+ }
- struct __charlist_result {
- bool __matched;
- bool __matched_digraph;
- size_t __new_pos;
- };
-
- static __charlist_result __exec_match_character_list(
- const __interpreter_info<_CharT>* const __code,
- const _CharT* const __last,
- const _CharT* const __current,
- const __global_execution_state& __gstate,
- size_t __current_pos) {
- static constexpr auto __buffer_size =
- std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1));
- _CharT __buffer[__buffer_size];
- for (size_t __i = 0; __i != __buffer_size; ++__i)
- __buffer[__i] = __code[__current_pos++].__char_;
- typename _Traits::char_class_type __mask;
- __builtin_memcpy(&__mask, __buffer, sizeof(typename _Traits::char_class_type));
-
- for (size_t __i = 0; __i != __buffer_size; ++__i)
- __buffer[__i] = __code[__current_pos++].__char_;
- typename _Traits::char_class_type __neg_mask;
- __builtin_memcpy(&__neg_mask, __buffer, sizeof(typename _Traits::char_class_type));
-
- auto __chars = __read_uleb(__code, __current_pos);
- auto __digraphs = __read_uleb(__code, __current_pos) * 2;
- auto __ranges = __read_uleb(__code, __current_pos) * 4;
- auto __neg_chars = __read_uleb(__code, __current_pos);
- auto __equiv_count = __read_uleb(__code, __current_pos);
- auto __equiv_size = __read_uleb(__code, __current_pos);
-
- bool __found = false;
-
- for (size_t __i = 0; __i != __chars; ++__i) {
- if (__code[__current_pos + __i].__char_ == *__current) {
- __found = true;
- break;
- }
- }
+ __current_pos += __chars;
- __current_pos += __chars;
+ if (__found) {
+ __current_pos += __digraphs + __ranges + __neg_chars + __equiv_size;
+ return {true, false, __current_pos};
+ }
+
+ if (__current + 1 != __last) {
+ _CharT __vals[2] = {__current[0], __current[1]};
- if (__found) {
- __current_pos += __digraphs + __ranges + __neg_chars + __equiv_size;
- return {true, false, __current_pos};
+ for (size_t __i = 0; __i != __digraphs; __i += 2) {
+ if (__code[__current_pos + __i].__char_ == __vals[0] && __code[__current_pos + __i + 1].__char_ == __vals[1]) {
+ __found = true;
+ break;
}
+ }
+ }
- if (__current + 1 != __last) {
- _CharT __vals[2] = {__current[0], __current[1]};
+ __current_pos += __digraphs;
- for (size_t __i = 0; __i != __digraphs; __i += 2) {
- if (__code[__current_pos + __i].__char_ == __vals[0] &&
- __code[__current_pos + __i + 1].__char_ == __vals[1]) {
- __found = true;
- break;
- }
- }
- }
+ if (__found) {
+ __current_pos += __ranges + __neg_chars + __equiv_size;
+ return {true, true, __current_pos};
+ }
- __current_pos += __digraphs;
+ auto __cmp = __gstate.__machine_.__traits_.transform(__current, __current + 1);
+ for (size_t __i = 0; __i != __ranges; __i += 4) {
+ _CharT __range_info[4];
+ std::transform(__gstate.__machine_.__machine_.begin() + __current_pos + __i,
+ __gstate.__machine_.__machine_.begin() + __current_pos + __i + 4,
+ __range_info,
+ [](__interpreter_info<_CharT> __val) { return __val.__char_; });
+ basic_string_view<_CharT> __min(__range_info, __range_info[1] == '\0' ? 1 : 2);
+ basic_string_view<_CharT> __max(__range_info + 2, __range_info[3] == '\0' ? 1 : 2);
+ if (__min <= __cmp && __cmp <= __max) {
+ __found = true;
+ break;
+ }
+ }
- if (__found) {
- __current_pos += __ranges + __neg_chars + __equiv_size;
- return {true, true, __current_pos};
- }
+ __current_pos += __ranges;
- auto __cmp = __gstate.__machine_.__traits_.transform(__current, __current + 1);
- for (size_t __i = 0; __i != __ranges; __i += 4) {
- _CharT __range_info[4];
- std::transform(__gstate.__machine_.__machine_.begin() + __current_pos + __i,
- __gstate.__machine_.__machine_.begin() + __current_pos + __i + 4,
- __range_info,
- [](__interpreter_info<_CharT> __val) { return __val.__char_; });
- basic_string_view<_CharT> __min(__range_info, __range_info[1] == '\0' ? 1 : 2);
- basic_string_view<_CharT> __max(__range_info + 2, __range_info[3] == '\0' ? 1 : 2);
- if (__min <= __cmp && __cmp <= __max) {
- __found = true;
- break;
- }
- }
+ if (__found) {
+ __current_pos += __neg_chars + __equiv_size;
+ return {true, false, __current_pos};
+ }
- __current_pos += __ranges;
+ if (__gstate.__machine_.__traits_.isctype(*__current, __mask)) {
+ return {true, false, __current_pos};
+ }
- if (__found) {
- __current_pos += __neg_chars + __equiv_size;
- return {true, false, __current_pos};
- }
+ bool __none_match = true;
+ for (size_t __i = 0; __i != __neg_chars; ++__i) {
+ if (__code[__current_pos + __i].__char_ == *__current) {
+ __none_match = false;
+ break;
+ }
+ }
- if (__gstate.__machine_.__traits_.isctype(*__current, __mask)) {
- return {true, false, __current_pos};
- }
+ __current_pos += __neg_chars;
- bool __none_match = true;
- for (size_t __i = 0; __i != __neg_chars; ++__i) {
- if (__code[__current_pos + __i].__char_ == *__current) {
- __none_match = false;
- break;
- }
- }
+ if (__none_match && __neg_mask != 0 && !__gstate.__machine_.__traits_.isctype(*__current, __neg_mask)) {
+ return {true, false, __current_pos};
+ }
- __current_pos += __neg_chars;
+ if (__found) {
+ __current_pos += __equiv_size;
+ return {true, false, __current_pos};
+ }
- if (__none_match && __neg_mask != 0 && !__gstate.__machine_.__traits_.isctype(*__current, __neg_mask)) {
- return {true, false, __current_pos};
- }
+ auto __after_pos = __current_pos + __equiv_size;
+ auto __transformed = __gstate.__machine_.__traits_.transform_primary(__current, __current + 1);
+ for (size_t __i = 0; __i != __equiv_count; ++__i) {
+ auto __size = __read_uleb(__code, __current_pos);
+ basic_string<_CharT> __str;
+ std::transform(__code + __current_pos,
+ __code + __current_pos + __size,
+ std::back_inserter(__str),
+ [](__interpreter_info<_CharT> __v) { return __v.__char_; });
+ __current_pos += __size;
+ if (__transformed == __str) {
+ __found = true;
+ break;
+ }
+ }
- if (__found) {
- __current_pos += __equiv_size;
- return {true, false, __current_pos};
- }
+ __current_pos = __after_pos;
- auto __after_pos = __current_pos + __equiv_size;
- auto __transformed = __gstate.__machine_.__traits_.transform_primary(__current, __current + 1);
- for (size_t __i = 0; __i != __equiv_count; ++__i) {
- auto __size = __read_uleb(__code, __current_pos);
- basic_string<_CharT> __str;
- std::transform(__code + __current_pos,
- __code + __current_pos + __size,
- std::back_inserter(__str),
- [](__interpreter_info<_CharT> __v) { return __v.__char_; });
- __current_pos += __size;
- if (__transformed == __str) {
- __found = true;
- break;
- }
- }
+ return {__found, false, __current_pos};
+ }
- __current_pos = __after_pos;
+ pair<bool, size_t> __exec_lookahead(
+ const _CharT* const __first,
+ const _CharT* const __last,
+ const __global_state& __gstate,
+ const __interpreter_info<_CharT>* const __code,
+ size_t __current_pos,
+ bool __is_positive) {
+ auto __jump_offset = __read_uleb(__code, __current_pos);
+ auto __submatch_count = __read_uleb(__code, __current_pos);
+ auto __submatch_base = __read_uleb(__code, __current_pos);
+ auto __loop_count = __read_uleb(__code, __current_pos);
+
+ unique_ptr<size_t[]> __initial_loop_values = std::make_unique_for_overwrite<size_t[]>(__loop_count);
+
+ for (size_t __i = 0; __i != __loop_count; ++__i)
+ __initial_loop_values[__i] = __read_uleb(__code, __current_pos);
+
+ __global_state __gexec_state{{}, __gstate.__machine_, __gstate.__flags_};
+ __gexec_state.__flags_ &= ~regex_constants::__full_match;
+ auto& __s = __gexec_state.__states_.emplace_back();
+ if (__loop_count > 0)
+ __s.__sub_matches_.resize(__submatch_count);
+ __s.__current_ = __current_;
+ __s.__loop_values_ = std::move(__initial_loop_values);
+ __s.__loop_starts_ = std::make_unique<const _CharT*[]>(__loop_count);
+ __s.__current_pos_ = __current_pos;
+ if (__gexec_state.__execute(__first, __last) != __is_positive)
+ return {false, __current_pos};
+ if (__is_positive) {
+ auto& __matched_state = __gexec_state.__states_.back();
+ std::copy(__matched_state.__sub_matches_.begin(),
+ __matched_state.__sub_matches_.end(),
+ __sub_matches_.begin() + __submatch_base);
+ }
+ __current_pos += __jump_offset;
+ return {true, __current_pos};
+ }
+
+ size_t __exec_branch_n_to_m_matcher(
+ __global_state& __gstate,
+ const __interpreter_info<_CharT>* const __code,
+ const _CharT* const __current,
+ size_t __current_pos,
+ bool __is_greedy) {
+ auto __loop_index = __read_uleb(__code, __current_pos);
+ auto __again_pos_base = __current_pos;
+ auto __again_pos = __again_pos_base - __read_uleb(__code, __current_pos);
+ if (__loop_values_[__loop_index] > 0) {
+ --__loop_values_[__loop_index];
+ __current_pos = __again_pos;
+ return __current_pos;
+ }
+ if (__loop_starts_[__loop_index] != __current && __loop_values_[__loop_index + 1] > 0) {
+ --__loop_values_[__loop_index + 1];
+ __loop_starts_[__loop_index] = __current;
+ __copy_to(__current, __gstate.__states_, __gstate);
+ if (!__is_greedy) {
+ __gstate.__states_.back().__current_pos_ = __again_pos;
+ } else {
+ __gstate.__states_.back().__current_pos_ = __current_pos;
+ __current_pos = __again_pos;
+ }
+ return __current_pos;
+ }
+ return __current_pos;
+ }
- return {__found, false, __current_pos};
+ pair<bool, size_t> __execute(const _CharT* __first, const _CharT* __last, __global_state& __gstate) {
+ const __interpreter_info<_CharT>* const __code = __gstate.__machine().data();
+ auto __current_pos = __current_pos_;
+ auto __counter = 0;
+ auto __current = __current_;
+ auto __commit_current = std::__make_scope_guard([&] { __current_ = __current; });
+ while (true) {
+ ++__counter;
+ auto __st = __code[__current_pos++].__state_;
+ switch (__st) {
+ using enum __state;
+
+ case __multiline_start_anchor:
+ if (!(__gstate.__flags_ & regex_constants::__at_first) && (__current[-1] == '\n' || __current[-1] == '\r'))
+ break;
+ [[__fallthrough__]];
+ case __start_anchor: {
+ if (__gstate.__flags_ & regex_constants::match_not_bol || !(__gstate.__flags_ & regex_constants::__at_first) ||
+ __first != __current)
+ return {false, __counter};
+ } break;
+
+ case __multiline_end_anchor:
+ if (__current[0] == '\r' || __current[0] == '\n')
+ break;
+ [[__fallthrough__]];
+ case __end_anchor: {
+ if (__gstate.__flags_ & regex_constants::match_not_eol || __current != __last)
+ return {false, __counter};
+ } break;
+
+ case __end_state: {
+ return {(!(__gstate.__flags_ & regex_constants::match_not_null) || __current != __first) &&
+ (!(__gstate.__flags_ & regex_constants::match_flag_type::__full_match) || __current == __last),
+ __counter};
}
- pair<bool, size_t> __exec_lookahead(
- const _CharT* const __first,
- const _CharT* const __last,
- const __global_execution_state& __gstate,
- const __interpreter_info<_CharT>* const __code,
- size_t __current_pos,
- bool __is_positive) {
- auto __jump_offset = __read_uleb(__code, __current_pos);
- auto __submatch_count = __read_uleb(__code, __current_pos);
- auto __submatch_base = __read_uleb(__code, __current_pos);
- auto __loop_count = __read_uleb(__code, __current_pos);
-
- unique_ptr<size_t[]> __initial_loop_values = std::make_unique_for_overwrite<size_t[]>(__loop_count);
-
- for (size_t __i = 0; __i != __loop_count; ++__i)
- __initial_loop_values[__i] = __read_uleb(__code, __current_pos);
-
- __global_execution_state __gexec_state{{}, __gstate.__machine_, __gstate.__flags_};
- __gexec_state.__flags_ &= ~regex_constants::__full_match;
- auto& __s = __gexec_state.__states_.emplace_back();
- if (__loop_count > 0)
- __s.__sub_matches_.resize(__submatch_count);
- __s.__current_ = __current_;
- __s.__loop_values_ = std::move(__initial_loop_values);
- __s.__loop_starts_ = std::make_unique<const _CharT*[]>(__loop_count);
- __s.__current_pos_ = __current_pos;
- if (__gexec_state.__execute(__first, __last) != __is_positive)
- return {false, __current_pos};
- if (__is_positive) {
- auto& __matched_state = __gexec_state.__states_.back();
- std::copy(__matched_state.__sub_matches_.begin(),
- __matched_state.__sub_matches_.end(),
- __sub_matches_.begin() + __submatch_base);
+ case __match_any: {
+ if (__current == __last)
+ return {false, __counter};
+ ++__current;
+ } break;
+
+ case __match_any_except_newline: {
+ if (__current == __last || *__current == '\r' || *__current == '\n')
+ return {false, __counter};
+ if constexpr (__is_same(_CharT, wchar_t)) {
+ if (*__current == 0x2028 || *__current == 0x2029)
+ return {false, __counter};
}
- __current_pos += __jump_offset;
- return {true, __current_pos};
+ ++__current;
+ } break;
+
+ case __match_char: {
+ if (__current == __last || *__current != __code[__current_pos++].__char_)
+ return {false, __counter};
+ ++__current;
+ } break;
+
+ case __match_icase_char: {
+ if (__current == __last ||
+ __gstate.__machine_.__traits_.translate_nocase(*__current) != __code[__current_pos++].__char_)
+ return {false, __counter};
+ ++__current;
+ } break;
+
+ case __branch_alternative: {
+ auto __offset = __read_uleb(__code, __current_pos);
+ __copy_to(__current, __gstate.__states_, __gstate);
+ __gstate.__states_.back().__current_pos_ = __current_pos + __offset;
+ break;
+ }
+
+ case __relative_jump: {
+ __current_pos += __read_uleb(__code, __current_pos);
+ break;
}
- size_t __exec_branch_n_to_m_matcher(
- __global_execution_state& __gstate,
- const __interpreter_info<_CharT>* const __code,
- const _CharT* const __current,
- size_t __current_pos,
- bool __is_greedy) {
- auto __loop_index = __read_uleb(__code, __current_pos);
- auto __again_pos_base = __current_pos;
- auto __again_pos = __again_pos_base - __read_uleb(__code, __current_pos);
- if (__loop_values_[__loop_index] > 0) {
- --__loop_values_[__loop_index];
- __current_pos = __again_pos;
- return __current_pos;
+ case __branch_n_to_m_matcher:
+ case __branch_nongreedy_n_to_m_matcher: {
+ __current_pos = __exec_branch_n_to_m_matcher(
+ __gstate, __code, __current, __current_pos, __st != __branch_nongreedy_n_to_m_matcher);
+ } break;
+
+ case __match_backref: {
+ sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
+ if (!__match.matched)
+ return {false, __counter};
+
+ auto __len = __match.second - __match.first;
+ if (__last - __current < __len || !std::equal(__match.first, __match.second, __current))
+ return {false, __counter};
+
+ __current += __len;
+ } break;
+
+ case __match_icase_backref: {
+ sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
+ if (!__match.matched)
+ return {false, __counter};
+
+ auto __len = __match.second - __match.first;
+ if (__last - __current < __len)
+ return {false, __counter};
+
+ for (ptrdiff_t __i = 0; __i != __len; ++__i) {
+ if (__gstate.__machine_.__traits_.translate_nocase(__match.first[__i]) !=
+ __gstate.__machine_.__traits_.translate_nocase(__current[__i]))
+ return {false, __counter};
}
- if (__loop_starts_[__loop_index] != __current && __loop_values_[__loop_index + 1] > 0) {
- --__loop_values_[__loop_index + 1];
- __loop_starts_[__loop_index] = __current;
- __copy_to(__current, __gstate.__states_, __gstate);
- if (!__is_greedy) {
- __gstate.__states_.back().__current_pos_ = __again_pos;
- } else {
- __gstate.__states_.back().__current_pos_ = __current_pos;
- __current_pos = __again_pos;
- }
- return __current_pos;
+
+ __current += __len;
+ } break;
+
+ case __match_character_list:
+ case __match_no_character_list: {
+ if (__current == __last)
+ return {false, __counter};
+ if (auto [__success, __digraph, __new_pos] =
+ __exec_match_character_list(__code, __last, __current, __gstate, __current_pos);
+ __success != (__st == __match_character_list))
+ return {false, __counter};
+ else {
+ __current_pos = __new_pos;
+ ++__current; // Swallow the matched character
+ if (__digraph)
+ ++__current; // Swallow the second character of a digraph
}
- return __current_pos;
+ } break;
+
+ case __marked_subexpression_begin: {
+ auto __match = __read_uleb(__code, __current_pos);
+ __sub_matches_[__match].first = __current;
+ } break;
+
+ case __marked_subexpression_end: {
+ auto __match = __read_uleb(__code, __current_pos);
+ __sub_matches_[__match].second = __current;
+ __sub_matches_[__match].matched = true;
+ } break;
+
+ case __match_word_boundary: {
+ if (!__is_word_boundary(__first, __last, __current, __gstate))
+ return {false, __counter};
+ } break;
+
+ case __match_no_word_boundary: {
+ if (__is_word_boundary(__first, __last, __current, __gstate))
+ return {false, __counter};
+ } break;
+
+ case __negative_lookahead:
+ case __positive_lookahead: {
+ if (auto __result =
+ __exec_lookahead(__first, __last, __gstate, __code, __current_pos, (__st == __positive_lookahead));
+ __result.first)
+ __current_pos = __result.second;
+ else
+ return {false, __counter};
+ } break;
+
+ default:
+ std::__libcpp_unreachable();
}
+ }
+ }
+};
- pair<bool, size_t> __execute(const _CharT* __first, const _CharT* __last, __global_execution_state& __gstate) {
- const __interpreter_info<_CharT>* const __code = __gstate.__machine().data();
- auto __current_pos = __current_pos_;
- auto __counter = 0;
- auto __current = __current_;
- auto __commit_current = std::__make_scope_guard([&] { __current_ = __current; });
- while (true) {
- ++__counter;
- auto __st = __code[__current_pos++].__state_;
- switch (__st) {
- using enum __state;
-
- case __multiline_start_anchor:
- if (!(__gstate.__flags_ & regex_constants::__at_first) && (__current[-1] == '\n' || __current[-1] == '\r'))
- break;
- [[__fallthrough__]];
- case __start_anchor: {
- if (__gstate.__flags_ & regex_constants::match_not_bol ||
- !(__gstate.__flags_ & regex_constants::__at_first) || __first != __current)
- return {false, __counter};
- } break;
-
- case __multiline_end_anchor:
- if (__current[0] == '\r' || __current[0] == '\n')
- break;
- [[__fallthrough__]];
- case __end_anchor: {
- if (__gstate.__flags_ & regex_constants::match_not_eol || __current != __last)
- return {false, __counter};
- } break;
-
- case __end_state: {
- return {(!(__gstate.__flags_ & regex_constants::match_not_null) || __current != __first) &&
- (!(__gstate.__flags_ & regex_constants::match_flag_type::__full_match) || __current == __last),
- __counter};
- }
+template <class _CharT, class _Traits>
+class __interpreter;
- case __match_any: {
- if (__current == __last)
- return {false, __counter};
- ++__current;
- } break;
-
- case __match_any_except_newline: {
- if (__current == __last || *__current == '\r' || *__current == '\n')
- return {false, __counter};
- if constexpr (__is_same(_CharT, wchar_t)) {
- if (*__current == 0x2028 || *__current == 0x2029)
- return {false, __counter};
- }
- ++__current;
- } break;
-
- case __match_char: {
- if (__current == __last || *__current != __code[__current_pos++].__char_)
- return {false, __counter};
- ++__current;
- } break;
-
- case __match_icase_char: {
- if (__current == __last ||
- __gstate.__machine_.__traits_.translate_nocase(*__current) != __code[__current_pos++].__char_)
- return {false, __counter};
- ++__current;
- } break;
-
- case __branch_alternative: {
- auto __offset = __read_uleb(__code, __current_pos);
- __copy_to(__current, __gstate.__states_, __gstate);
- __gstate.__states_.back().__current_pos_ = __current_pos + __offset;
- break;
- }
+template <class _CharT, class _Traits>
+struct __global_execution_state {
+ vector<__local_execution_state<_CharT, _Traits>> __states_;
+ const __interpreter<_CharT, _Traits>& __machine_;
+ regex_constants::match_flag_type __flags_;
- case __relative_jump: {
- __current_pos += __read_uleb(__code, __current_pos);
- break;
- }
+ const vector<__interpreter_info<_CharT>>& __machine() { return __machine_.__machine_; }
- case __branch_n_to_m_matcher:
- case __branch_nongreedy_n_to_m_matcher: {
- __current_pos = __exec_branch_n_to_m_matcher(
- __gstate, __code, __current, __current_pos, __st != __branch_nongreedy_n_to_m_matcher);
- } break;
-
- case __match_backref: {
- sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
- if (!__match.matched)
- return {false, __counter};
-
- auto __len = __match.second - __match.first;
- if (__last - __current < __len || !std::equal(__match.first, __match.second, __current))
- return {false, __counter};
-
- __current += __len;
- } break;
-
- case __match_icase_backref: {
- sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
- if (!__match.matched)
- return {false, __counter};
-
- auto __len = __match.second - __match.first;
- if (__last - __current < __len)
- return {false, __counter};
-
- for (ptrdiff_t __i = 0; __i != __len; ++__i) {
- if (__gstate.__machine_.__traits_.translate_nocase(__match.first[__i]) !=
- __gstate.__machine_.__traits_.translate_nocase(__current[__i]))
- return {false, __counter};
- }
-
- __current += __len;
- } break;
-
- case __match_character_list:
- case __match_no_character_list: {
- if (__current == __last)
- return {false, __counter};
- if (auto [__success, __digraph, __new_pos] =
- __exec_match_character_list(__code, __last, __current, __gstate, __current_pos);
- __success != (__st == __match_character_list))
- return {false, __counter};
- else {
- __current_pos = __new_pos;
- ++__current; // Swallow the matched character
- if (__digraph)
- ++__current; // Swallow the second character of a digraph
- }
- } break;
-
- case __marked_subexpression_begin: {
- auto __match = __read_uleb(__code, __current_pos);
- __sub_matches_[__match].first = __current;
- } break;
-
- case __marked_subexpression_end: {
- auto __match = __read_uleb(__code, __current_pos);
- __sub_matches_[__match].second = __current;
- __sub_matches_[__match].matched = true;
- } break;
-
- case __match_word_boundary: {
- if (!__is_word_boundary(__first, __last, __current, __gstate))
- return {false, __counter};
- } break;
-
- case __match_no_word_boundary: {
- if (__is_word_boundary(__first, __last, __current, __gstate))
- return {false, __counter};
- } break;
-
- case __negative_lookahead:
- case __positive_lookahead: {
- if (auto __result =
- __exec_lookahead(__first, __last, __gstate, __code, __current_pos, (__st == __positive_lookahead));
- __result.first)
- __current_pos = __result.second;
- else
- return {false, __counter};
- } break;
-
- default:
- std::__libcpp_unreachable();
+ bool __execute(const _CharT* __first, const _CharT* __last) {
+ size_t __length = __last - __first + 1;
+ if (__machine_.__find_longest_) {
+ __local_execution_state<_CharT, _Traits> __best_state;
+ bool __found_match = false;
+ size_t __gcounter = 0;
+ while (!__states_.empty()) {
+ if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ std::__throw_regex_error<regex_constants::error_complexity>();
+ auto __state = std::move(__states_.back());
+ __states_.pop_back();
+ auto [__success, __counter] = __state.__execute(__first, __last, *this);
+ __gcounter += __counter;
+ if (__success) {
+ if (!__found_match || __best_state.__current_ < __state.__current_)
+ __best_state = std::move(__state);
+ if (__best_state.__current_ == __last) {
+ __states_.push_back(std::move(__best_state));
+ return true;
}
+ __found_match = true;
}
}
- };
-
- const vector<__interpreter_info<_CharT>>& __machine() { return __machine_.__machine_; }
-
- bool __execute(const _CharT* __first, const _CharT* __last) {
- size_t __length = __last - __first + 1;
- if (__machine_.__find_longest_) {
- __local_execution_state __best_state;
- bool __found_match = false;
- size_t __gcounter = 0;
- while (!__states_.empty()) {
- if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
- std::__throw_regex_error<regex_constants::error_complexity>();
- auto __state = std::move(__states_.back());
- __states_.pop_back();
- auto [__success, __counter] = __state.__execute(__first, __last, *this);
+ __states_.push_back(std::move(__best_state));
+ return __found_match;
+ } else {
+ size_t __gcounter = 0;
+ while (!__states_.empty()) {
+ if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ std::__throw_regex_error<regex_constants::error_complexity>();
+ auto __state = std::move(__states_.back());
+ __states_.pop_back();
+ if (auto [__success, __counter] = __state.__execute(__first, __last, *this); __success) {
+ __states_.push_back(std::move(__state));
+ return true;
+ } else {
__gcounter += __counter;
- if (__success) {
- if (!__found_match || __best_state.__current_ < __state.__current_)
- __best_state = std::move(__state);
- if (__best_state.__current_ == __last) {
- __states_.push_back(std::move(__best_state));
- return true;
- }
- __found_match = true;
- }
- }
- __states_.push_back(std::move(__best_state));
- return __found_match;
- } else {
- size_t __gcounter = 0;
- while (!__states_.empty()) {
- if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
- std::__throw_regex_error<regex_constants::error_complexity>();
- auto __state = std::move(__states_.back());
- __states_.pop_back();
- if (auto [__success, __counter] = __state.__execute(__first, __last, *this); __success) {
- __states_.push_back(std::move(__state));
- return true;
- } else {
- __gcounter += __counter;
- }
}
- return false;
}
+ return false;
}
- };
+ }
+};
+
+template <class _CharT, class _Traits>
+class __interpreter {
+ friend __local_execution_state<_CharT, _Traits>;
+ friend __global_execution_state<_CharT, _Traits>;
+
+ vector<__interpreter_info<_CharT> > __machine_;
+ vector<size_t> __initial_loop_values_;
+ _Traits __traits_;
+ bool __find_longest_;
void push_back(__interpreter_info<_CharT> __info) { __machine_.push_back(__info); }
@@ -797,7 +803,7 @@ class __interpreter {
const _CharT* __first,
const _CharT* __last,
vector<sub_match<const _CharT*>>& __sub_matches) const {
- using __local_state = typename __global_execution_state::__local_execution_state;
+ using __local_state = __local_execution_state<_CharT, _Traits>;
__local_state __base_state{
.__current_ = __first,
>From 9ef0af3afbc86b9c3279bb4999cef1ab27153fc6 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 29 Mar 2026 03:50:24 +0200
Subject: [PATCH 07/21] [libc++] Make the sub_match representation more compact
for running the interpreter
---
libcxx/include/__regex/interpreter.h | 36 ++++++++++++++++++----------
1 file changed, 23 insertions(+), 13 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 5a52d5bb26eeb..4355b644b0306 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -154,7 +154,7 @@ struct __local_execution_state {
using __global_state = __global_execution_state<_CharT, _Traits>;
const _CharT* __current_;
- vector<sub_match<const _CharT*> > __sub_matches_;
+ vector<pair<const _CharT*, const _CharT*>> __sub_matches_;
size_t __current_pos_;
unique_ptr<size_t[]> __loop_values_;
unique_ptr<const _CharT*[]> __loop_starts_;
@@ -497,8 +497,8 @@ struct __local_execution_state {
} break;
case __match_backref: {
- sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
- if (!__match.matched)
+ auto& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
+ if (__match.first == nullptr)
return {false, __counter};
auto __len = __match.second - __match.first;
@@ -509,8 +509,8 @@ struct __local_execution_state {
} break;
case __match_icase_backref: {
- sub_match<const _CharT*>& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
- if (!__match.matched)
+ auto& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
+ if (__match.first == nullptr)
return {false, __counter};
auto __len = __match.second - __match.first;
@@ -548,9 +548,8 @@ struct __local_execution_state {
} break;
case __marked_subexpression_end: {
- auto __match = __read_uleb(__code, __current_pos);
- __sub_matches_[__match].second = __current;
- __sub_matches_[__match].matched = true;
+ auto __match = __read_uleb(__code, __current_pos);
+ __sub_matches_[__match].second = __current;
} break;
case __match_word_boundary: {
@@ -805,9 +804,20 @@ class __interpreter {
vector<sub_match<const _CharT*>>& __sub_matches) const {
using __local_state = __local_execution_state<_CharT, _Traits>;
+ auto __copy_to_submatches =
+ [&](const vector<pair<const _CharT*, const _CharT*>>& __from, vector<sub_match<const _CharT*>>& __to) {
+ std::transform(__from.begin(), __from.end(), __to.begin(), [&](pair<const _CharT*, const _CharT*> __v) {
+ sub_match<const _CharT*> __ret;
+ __ret.first = __v.first ? __v.first : __last;
+ __ret.second = __v.first ? __v.second : __last;
+ __ret.matched = __v.first;
+ return __ret;
+ });
+ };
+
__local_state __base_state{
.__current_ = __first,
- .__sub_matches_ = std::move(__sub_matches),
+ .__sub_matches_ = vector<pair<const _CharT*, const _CharT*>>(__sub_matches.size()),
.__current_pos_ = 0,
.__loop_values_ = __initial_loop_values_.empty()
? nullptr
@@ -836,7 +846,7 @@ class __interpreter {
if (!__found_match || __best_state.__current_ < __state.__current_)
__best_state = std::move(__state);
if (__best_state.__current_ == __last) {
- __sub_matches = std::move(__best_state.__sub_matches_);
+ __copy_to_submatches(__best_state.__sub_matches_, __sub_matches);
return {true, __best_state.__current_};
}
__found_match = true;
@@ -844,11 +854,11 @@ class __interpreter {
}
if (!__found_match)
return {false, {}};
- __sub_matches = std::move(__best_state.__sub_matches_);
+ __copy_to_submatches(__best_state.__sub_matches_, __sub_matches);
return {true, __best_state.__current_};
} else {
if (__base_state_matched) {
- __sub_matches = std::move(__base_state.__sub_matches_);
+ __copy_to_submatches(__base_state.__sub_matches_, __sub_matches);
return {true, __base_state.__current_};
}
while (!__gexec_state.__states_.empty()) {
@@ -857,7 +867,7 @@ class __interpreter {
auto __state = std::move(__gexec_state.__states_.back());
__gexec_state.__states_.pop_back();
if (auto [__success, __counter] = __state.__execute(__first, __last, __gexec_state); __success) {
- __sub_matches = std::move(__state.__sub_matches_);
+ __copy_to_submatches(__state.__sub_matches_, __sub_matches);
return {true, __state.__current_};
} else {
__gcounter += __counter;
>From d515e58b1191baf6df1a9ca686050796a84c6836 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 30 Mar 2026 03:12:13 +0200
Subject: [PATCH 08/21] Avoid allocating sub_matches
---
libcxx/include/__regex/interpreter.h | 29 +++++++++++++++-------------
libcxx/include/regex | 4 ++++
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 4355b644b0306..c113fb6b85951 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -801,23 +801,26 @@ class __interpreter {
__execute(regex_constants::match_flag_type __flags,
const _CharT* __first,
const _CharT* __last,
+ size_t __submatch_count,
vector<sub_match<const _CharT*>>& __sub_matches) const {
using __local_state = __local_execution_state<_CharT, _Traits>;
auto __copy_to_submatches =
[&](const vector<pair<const _CharT*, const _CharT*>>& __from, vector<sub_match<const _CharT*>>& __to) {
- std::transform(__from.begin(), __from.end(), __to.begin(), [&](pair<const _CharT*, const _CharT*> __v) {
- sub_match<const _CharT*> __ret;
- __ret.first = __v.first ? __v.first : __last;
- __ret.second = __v.first ? __v.second : __last;
- __ret.matched = __v.first;
- return __ret;
- });
+ __to.clear();
+ std::transform(
+ __from.begin(), __from.end(), std::back_inserter(__to), [&](pair<const _CharT*, const _CharT*> __v) {
+ sub_match<const _CharT*> __ret;
+ __ret.first = __v.first ? __v.first : __last;
+ __ret.second = __v.first ? __v.second : __last;
+ __ret.matched = __v.first;
+ return __ret;
+ });
};
__local_state __base_state{
.__current_ = __first,
- .__sub_matches_ = vector<pair<const _CharT*, const _CharT*>>(__sub_matches.size()),
+ .__sub_matches_ = vector<pair<const _CharT*, const _CharT*>>(__submatch_count),
.__current_pos_ = 0,
.__loop_values_ = __initial_loop_values_.empty()
? nullptr
@@ -884,12 +887,13 @@ class __interpreter {
__unmatched.second = __last;
__unmatched.matched = false;
- vector<sub_match<const _CharT*>> __sub_matches(__marked_count, __unmatched);
+ vector<sub_match<const _CharT*>> __sub_matches;
if (auto [__success, __last_val] = __execute(
__flags | ((__flags & regex_constants::__no_update_pos) ? regex_constants::match_flag_type()
: regex_constants::__at_first),
__first,
__last,
+ __marked_count,
__sub_matches);
__success) {
return {__first, __last_val, std::move(__sub_matches)};
@@ -901,14 +905,13 @@ class __interpreter {
__flags |= regex_constants::match_prev_avail;
for (++__first; __first != __last; ++__first) {
- __sub_matches.assign(__marked_count, __unmatched);
- if (auto [__success, __last_val] = __execute(__flags, __first, __last, __sub_matches); __success) {
+ if (auto [__success, __last_val] = __execute(__flags, __first, __last, __marked_count, __sub_matches);
+ __success) {
return {__first, __last_val, std::move(__sub_matches)};
}
}
- __sub_matches.assign(__marked_count, __unmatched);
- if (auto [__success, __last_val] = __execute(__flags, __first, __last, __sub_matches); __success) {
+ if (auto [__success, __last_val] = __execute(__flags, __first, __last, __marked_count, __sub_matches); __success) {
return {__first, __last_val, std::move(__sub_matches)};
}
diff --git a/libcxx/include/regex b/libcxx/include/regex
index c0011c954cc26..87dc675960757 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -1292,6 +1292,7 @@ public:
__state.__flags_ | (__state.__at_first_ ? regex_constants::__at_first : regex_constants::match_flag_type()),
__state.__first_,
__state.__last_,
+ __state.__sub_matches_.size(),
__state.__sub_matches_);
__state.__do_ = __res.first ? std::__state<_CharT>::__end_state : std::__state<_CharT>::__reject;
__state.__current_ = __res.second;
@@ -1306,6 +1307,9 @@ public:
}
};
+static_assert(sizeof(__regex::__global_execution_state<char, regex_traits<char>>) == 40);
+static_assert(sizeof(__regex::__local_execution_state<char, regex_traits<char>>) == 56);
+
template <class _CharT, class _Traits = regex_traits<_CharT> >
class basic_regex;
>From 26239ece621942107144d65eab0da581f0383534 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 30 Mar 2026 04:27:43 +0200
Subject: [PATCH 09/21] Avoid extra __local_state on the stack
---
libcxx/include/__regex/interpreter.h | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index c113fb6b85951..c321994eaa33e 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -836,8 +836,9 @@ class __interpreter {
size_t __length = __last - __first + 1;
if (__gexec_state.__machine_.__find_longest_) {
- __local_state __best_state = __base_state_matched ? std::move(__base_state) : __local_state{};
- bool __found_match = __base_state_matched;
+ if (!__base_state_matched)
+ __base_state.__current_ = __first;
+ bool __found_match = __base_state_matched;
while (!__gexec_state.__states_.empty()) {
if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
std::__throw_regex_error<regex_constants::error_complexity>();
@@ -846,19 +847,19 @@ class __interpreter {
auto [__success, __counter] = __state.__execute(__first, __last, __gexec_state);
__gcounter += __counter;
if (__success) {
- if (!__found_match || __best_state.__current_ < __state.__current_)
- __best_state = std::move(__state);
- if (__best_state.__current_ == __last) {
- __copy_to_submatches(__best_state.__sub_matches_, __sub_matches);
- return {true, __best_state.__current_};
+ if (!__found_match || __base_state.__current_ < __state.__current_)
+ __base_state = std::move(__state);
+ if (__base_state.__current_ == __last) {
+ __copy_to_submatches(__base_state.__sub_matches_, __sub_matches);
+ return {true, __base_state.__current_};
}
__found_match = true;
}
}
if (!__found_match)
return {false, {}};
- __copy_to_submatches(__best_state.__sub_matches_, __sub_matches);
- return {true, __best_state.__current_};
+ __copy_to_submatches(__base_state.__sub_matches_, __sub_matches);
+ return {true, __base_state.__current_};
} else {
if (__base_state_matched) {
__copy_to_submatches(__base_state.__sub_matches_, __sub_matches);
@@ -867,11 +868,11 @@ class __interpreter {
while (!__gexec_state.__states_.empty()) {
if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
std::__throw_regex_error<regex_constants::error_complexity>();
- auto __state = std::move(__gexec_state.__states_.back());
+ __base_state = std::move(__gexec_state.__states_.back());
__gexec_state.__states_.pop_back();
- if (auto [__success, __counter] = __state.__execute(__first, __last, __gexec_state); __success) {
- __copy_to_submatches(__state.__sub_matches_, __sub_matches);
- return {true, __state.__current_};
+ if (auto [__success, __counter] = __base_state.__execute(__first, __last, __gexec_state); __success) {
+ __copy_to_submatches(__base_state.__sub_matches_, __sub_matches);
+ return {true, __base_state.__current_};
} else {
__gcounter += __counter;
}
>From f7ed041393a8c68d77e78daec267012505f4d2d9 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 30 Mar 2026 11:08:04 +0200
Subject: [PATCH 10/21] Make local state smaller
---
libcxx/include/__regex/interpreter.h | 46 +++++++++++++++-------------
libcxx/include/regex | 2 +-
2 files changed, 26 insertions(+), 22 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index c321994eaa33e..9cc2dab5ce036 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -146,6 +146,16 @@ struct __search_result {
~__search_result() {}
};
+template <class _CharT>
+union __loop_value {
+ __loop_value() = default;
+ __loop_value(size_t __v) : __int_(__v) {}
+ __loop_value(const _CharT* __v) : __ptr_(__v) {}
+
+ size_t __int_;
+ const _CharT* __ptr_;
+};
+
template <class _CharT, class _Traits>
struct __global_execution_state;
@@ -156,8 +166,7 @@ struct __local_execution_state {
const _CharT* __current_;
vector<pair<const _CharT*, const _CharT*>> __sub_matches_;
size_t __current_pos_;
- unique_ptr<size_t[]> __loop_values_;
- unique_ptr<const _CharT*[]> __loop_starts_;
+ unique_ptr<__loop_value<_CharT>[]> __loop_values_;
static pair<size_t, size_t>
__read_uleb_impl(_LIBCPP_NOESCAPE const __interpreter_info<_CharT>* __machine, size_t __current_pos) {
@@ -185,12 +194,9 @@ struct __local_execution_state {
void __copy_to(const _CharT* const __current, vector<__local_execution_state>& __vec, __global_state& __gstate) {
auto __loop_value_count = __gstate.__machine_.__initial_loop_values_.size();
- auto __loop_values_copy = std::make_unique_for_overwrite<size_t[]>(__loop_value_count);
+ auto __loop_values_copy = std::make_unique_for_overwrite<__loop_value<_CharT>[]>(__loop_value_count);
std::copy_n(__loop_values_.get(), __loop_value_count, __loop_values_copy.get());
- auto __loop_starts_copy = std::make_unique_for_overwrite<const _CharT*[]>(__loop_value_count);
- std::copy_n(__loop_starts_.get(), __loop_value_count, __loop_starts_copy.get());
- __vec.emplace_back(
- __current, __sub_matches_, __current_pos_, std::move(__loop_values_copy), std::move(__loop_starts_copy));
+ __vec.emplace_back(__current, __sub_matches_, __current_pos_, std::move(__loop_values_copy));
}
static bool __is_word_boundary(
@@ -357,7 +363,7 @@ struct __local_execution_state {
auto __submatch_base = __read_uleb(__code, __current_pos);
auto __loop_count = __read_uleb(__code, __current_pos);
- unique_ptr<size_t[]> __initial_loop_values = std::make_unique_for_overwrite<size_t[]>(__loop_count);
+ auto __initial_loop_values = std::make_unique_for_overwrite<__loop_value<_CharT>[]>(__loop_count);
for (size_t __i = 0; __i != __loop_count; ++__i)
__initial_loop_values[__i] = __read_uleb(__code, __current_pos);
@@ -369,7 +375,6 @@ struct __local_execution_state {
__s.__sub_matches_.resize(__submatch_count);
__s.__current_ = __current_;
__s.__loop_values_ = std::move(__initial_loop_values);
- __s.__loop_starts_ = std::make_unique<const _CharT*[]>(__loop_count);
__s.__current_pos_ = __current_pos;
if (__gexec_state.__execute(__first, __last) != __is_positive)
return {false, __current_pos};
@@ -392,14 +397,14 @@ struct __local_execution_state {
auto __loop_index = __read_uleb(__code, __current_pos);
auto __again_pos_base = __current_pos;
auto __again_pos = __again_pos_base - __read_uleb(__code, __current_pos);
- if (__loop_values_[__loop_index] > 0) {
- --__loop_values_[__loop_index];
+ if (__loop_values_[__loop_index + 1].__int_ > 0) {
+ --__loop_values_[__loop_index + 1].__int_;
__current_pos = __again_pos;
return __current_pos;
}
- if (__loop_starts_[__loop_index] != __current && __loop_values_[__loop_index + 1] > 0) {
- --__loop_values_[__loop_index + 1];
- __loop_starts_[__loop_index] = __current;
+ if (__loop_values_[__loop_index].__ptr_ != __current && __loop_values_[__loop_index + 2].__int_ > 0) {
+ --__loop_values_[__loop_index + 2].__int_;
+ __loop_values_[__loop_index] = __current;
__copy_to(__current, __gstate.__states_, __gstate);
if (!__is_greedy) {
__gstate.__states_.back().__current_pos_ = __again_pos;
@@ -640,7 +645,7 @@ class __interpreter {
friend __global_execution_state<_CharT, _Traits>;
vector<__interpreter_info<_CharT> > __machine_;
- vector<size_t> __initial_loop_values_;
+ vector<__loop_value<_CharT>> __initial_loop_values_;
_Traits __traits_;
bool __find_longest_;
@@ -720,6 +725,7 @@ class __interpreter {
push_back(__greedy ? __state::__branch_n_to_m_matcher : __state::__branch_nongreedy_n_to_m_matcher);
__write_uleb(__machine_, __initial_loop_values_.size());
__write_uleb(__machine_, size() - __expr_start);
+ __initial_loop_values_.push_back(nullptr);
__initial_loop_values_.push_back(__min);
__initial_loop_values_.push_back(__max - __min);
}
@@ -771,7 +777,7 @@ class __interpreter {
void __push_no_word_boundary() { push_back(__state::__match_no_word_boundary); }
struct __lookahead_info {
- vector<size_t> __initial_loop_values_;
+ vector<__loop_value<_CharT>> __initial_loop_values_;
size_t __lookahead_start_;
};
@@ -790,8 +796,8 @@ class __interpreter {
__write_uleb(__buffer, __marked_count);
__write_uleb(__buffer, __marked_base);
__write_uleb(__buffer, __initial_loop_values_.size());
- for (size_t __val : __initial_loop_values_)
- __write_uleb(__buffer, __val);
+ for (__loop_value<_CharT> __val : __initial_loop_values_)
+ __write_uleb(__buffer, __val.__int_);
insert(__info.__lookahead_start_, __buffer);
}
@@ -824,9 +830,7 @@ class __interpreter {
.__current_pos_ = 0,
.__loop_values_ = __initial_loop_values_.empty()
? nullptr
- : std::make_unique_for_overwrite<size_t[]>(__initial_loop_values_.size()),
- .__loop_starts_ =
- __initial_loop_values_.empty() ? nullptr : std::make_unique<const _CharT*[]>(__initial_loop_values_.size()),
+ : std::make_unique_for_overwrite<__loop_value<_CharT>[]>(__initial_loop_values_.size()),
};
if (!__initial_loop_values_.empty())
std::copy(__initial_loop_values_.begin(), __initial_loop_values_.end(), __base_state.__loop_values_.get());
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 87dc675960757..afef6f985b9c4 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -1308,7 +1308,7 @@ public:
};
static_assert(sizeof(__regex::__global_execution_state<char, regex_traits<char>>) == 40);
-static_assert(sizeof(__regex::__local_execution_state<char, regex_traits<char>>) == 56);
+static_assert(sizeof(__regex::__local_execution_state<char, regex_traits<char>>) == 48);
template <class _CharT, class _Traits = regex_traits<_CharT> >
class basic_regex;
>From 4fd5f16edd278c0c4b73ecdc1fa54313dedf7e36 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 30 Mar 2026 11:33:01 +0200
Subject: [PATCH 11/21] Make the local state more compact
---
libcxx/include/__regex/interpreter.h | 35 +++++++++++++++-------------
libcxx/include/regex | 4 ++--
2 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 9cc2dab5ce036..4f32620287b3e 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -164,7 +164,7 @@ struct __local_execution_state {
using __global_state = __global_execution_state<_CharT, _Traits>;
const _CharT* __current_;
- vector<pair<const _CharT*, const _CharT*>> __sub_matches_;
+ unique_ptr<pair<const _CharT*, const _CharT*>[]> __sub_matches_;
size_t __current_pos_;
unique_ptr<__loop_value<_CharT>[]> __loop_values_;
@@ -196,7 +196,10 @@ struct __local_execution_state {
auto __loop_value_count = __gstate.__machine_.__initial_loop_values_.size();
auto __loop_values_copy = std::make_unique_for_overwrite<__loop_value<_CharT>[]>(__loop_value_count);
std::copy_n(__loop_values_.get(), __loop_value_count, __loop_values_copy.get());
- __vec.emplace_back(__current, __sub_matches_, __current_pos_, std::move(__loop_values_copy));
+ auto __sub_matches =
+ std::make_unique_for_overwrite<pair<const _CharT*, const _CharT*>[]>(__gstate.__submatch_count_);
+ std::copy_n(__sub_matches_.get(), __gstate.__submatch_count_, __sub_matches.get());
+ __vec.emplace_back(__current, std::move(__sub_matches), __current_pos_, std::move(__loop_values_copy));
}
static bool __is_word_boundary(
@@ -368,11 +371,11 @@ struct __local_execution_state {
for (size_t __i = 0; __i != __loop_count; ++__i)
__initial_loop_values[__i] = __read_uleb(__code, __current_pos);
- __global_state __gexec_state{{}, __gstate.__machine_, __gstate.__flags_};
+ __global_state __gexec_state{{}, __gstate.__machine_, __submatch_count, __gstate.__flags_};
__gexec_state.__flags_ &= ~regex_constants::__full_match;
auto& __s = __gexec_state.__states_.emplace_back();
if (__loop_count > 0)
- __s.__sub_matches_.resize(__submatch_count);
+ __s.__sub_matches_ = std::make_unique<pair<const _CharT*, const _CharT*>[]>(__submatch_count);
__s.__current_ = __current_;
__s.__loop_values_ = std::move(__initial_loop_values);
__s.__current_pos_ = __current_pos;
@@ -380,9 +383,7 @@ struct __local_execution_state {
return {false, __current_pos};
if (__is_positive) {
auto& __matched_state = __gexec_state.__states_.back();
- std::copy(__matched_state.__sub_matches_.begin(),
- __matched_state.__sub_matches_.end(),
- __sub_matches_.begin() + __submatch_base);
+ std::copy_n(__matched_state.__sub_matches_.get(), __submatch_count, __sub_matches_.get() + __submatch_base);
}
__current_pos += __jump_offset;
return {true, __current_pos};
@@ -591,6 +592,7 @@ template <class _CharT, class _Traits>
struct __global_execution_state {
vector<__local_execution_state<_CharT, _Traits>> __states_;
const __interpreter<_CharT, _Traits>& __machine_;
+ size_t __submatch_count_;
regex_constants::match_flag_type __flags_;
const vector<__interpreter_info<_CharT>>& __machine() { return __machine_.__machine_; }
@@ -812,10 +814,10 @@ class __interpreter {
using __local_state = __local_execution_state<_CharT, _Traits>;
auto __copy_to_submatches =
- [&](const vector<pair<const _CharT*, const _CharT*>>& __from, vector<sub_match<const _CharT*>>& __to) {
+ [&](pair<const _CharT*, const _CharT*>* __from, size_t __count, vector<sub_match<const _CharT*>>& __to) {
__to.clear();
std::transform(
- __from.begin(), __from.end(), std::back_inserter(__to), [&](pair<const _CharT*, const _CharT*> __v) {
+ __from, __from + __count, std::back_inserter(__to), [&](pair<const _CharT*, const _CharT*> __v) {
sub_match<const _CharT*> __ret;
__ret.first = __v.first ? __v.first : __last;
__ret.second = __v.first ? __v.second : __last;
@@ -825,8 +827,9 @@ class __interpreter {
};
__local_state __base_state{
- .__current_ = __first,
- .__sub_matches_ = vector<pair<const _CharT*, const _CharT*>>(__submatch_count),
+ .__current_ = __first,
+ .__sub_matches_ =
+ __submatch_count ? std::make_unique<pair<const _CharT*, const _CharT*>[]>(__submatch_count) : nullptr,
.__current_pos_ = 0,
.__loop_values_ = __initial_loop_values_.empty()
? nullptr
@@ -835,7 +838,7 @@ class __interpreter {
if (!__initial_loop_values_.empty())
std::copy(__initial_loop_values_.begin(), __initial_loop_values_.end(), __base_state.__loop_values_.get());
- __global_execution_state __gexec_state{{}, *this, __flags};
+ __global_execution_state __gexec_state{{}, *this, __submatch_count, __flags};
auto [__base_state_matched, __gcounter] = __base_state.__execute(__first, __last, __gexec_state);
size_t __length = __last - __first + 1;
@@ -854,7 +857,7 @@ class __interpreter {
if (!__found_match || __base_state.__current_ < __state.__current_)
__base_state = std::move(__state);
if (__base_state.__current_ == __last) {
- __copy_to_submatches(__base_state.__sub_matches_, __sub_matches);
+ __copy_to_submatches(__base_state.__sub_matches_.get(), __submatch_count, __sub_matches);
return {true, __base_state.__current_};
}
__found_match = true;
@@ -862,11 +865,11 @@ class __interpreter {
}
if (!__found_match)
return {false, {}};
- __copy_to_submatches(__base_state.__sub_matches_, __sub_matches);
+ __copy_to_submatches(__base_state.__sub_matches_.get(), __submatch_count, __sub_matches);
return {true, __base_state.__current_};
} else {
if (__base_state_matched) {
- __copy_to_submatches(__base_state.__sub_matches_, __sub_matches);
+ __copy_to_submatches(__base_state.__sub_matches_.get(), __submatch_count, __sub_matches);
return {true, __base_state.__current_};
}
while (!__gexec_state.__states_.empty()) {
@@ -875,7 +878,7 @@ class __interpreter {
__base_state = std::move(__gexec_state.__states_.back());
__gexec_state.__states_.pop_back();
if (auto [__success, __counter] = __base_state.__execute(__first, __last, __gexec_state); __success) {
- __copy_to_submatches(__base_state.__sub_matches_, __sub_matches);
+ __copy_to_submatches(__base_state.__sub_matches_.get(), __submatch_count, __sub_matches);
return {true, __base_state.__current_};
} else {
__gcounter += __counter;
diff --git a/libcxx/include/regex b/libcxx/include/regex
index afef6f985b9c4..13492357a059d 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -1307,8 +1307,8 @@ public:
}
};
-static_assert(sizeof(__regex::__global_execution_state<char, regex_traits<char>>) == 40);
-static_assert(sizeof(__regex::__local_execution_state<char, regex_traits<char>>) == 48);
+static_assert(sizeof(__regex::__global_execution_state<char, regex_traits<char>>) == 48);
+static_assert(sizeof(__regex::__local_execution_state<char, regex_traits<char>>) == 32);
template <class _CharT, class _Traits = regex_traits<_CharT> >
class basic_regex;
>From 25585dcc4b57694bc3bd52f04dedd0163777dd6d Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 31 Mar 2026 03:08:52 +0200
Subject: [PATCH 12/21] Keep global state around
---
libcxx/include/__regex/interpreter.h | 56 +++++++++++++++-----------
libcxx/include/regex | 2 +-
libcxx/test/benchmarks/regex.bench.cpp | 11 +++++
3 files changed, 45 insertions(+), 24 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 4f32620287b3e..9d5bf86bb7ca7 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -806,10 +806,9 @@ class __interpreter {
size_t size() const { return __machine_.size(); }
pair<bool, const _CharT*>
- __execute(regex_constants::match_flag_type __flags,
+ __execute(__global_execution_state<_CharT, _Traits>& __gexec_state,
const _CharT* __first,
const _CharT* __last,
- size_t __submatch_count,
vector<sub_match<const _CharT*>>& __sub_matches) const {
using __local_state = __local_execution_state<_CharT, _Traits>;
@@ -827,9 +826,10 @@ class __interpreter {
};
__local_state __base_state{
- .__current_ = __first,
- .__sub_matches_ =
- __submatch_count ? std::make_unique<pair<const _CharT*, const _CharT*>[]>(__submatch_count) : nullptr,
+ .__current_ = __first,
+ .__sub_matches_ = __gexec_state.__submatch_count_
+ ? std::make_unique<pair<const _CharT*, const _CharT*>[]>(__gexec_state.__submatch_count_)
+ : nullptr,
.__current_pos_ = 0,
.__loop_values_ = __initial_loop_values_.empty()
? nullptr
@@ -838,7 +838,6 @@ class __interpreter {
if (!__initial_loop_values_.empty())
std::copy(__initial_loop_values_.begin(), __initial_loop_values_.end(), __base_state.__loop_values_.get());
- __global_execution_state __gexec_state{{}, *this, __submatch_count, __flags};
auto [__base_state_matched, __gcounter] = __base_state.__execute(__first, __last, __gexec_state);
size_t __length = __last - __first + 1;
@@ -857,7 +856,7 @@ class __interpreter {
if (!__found_match || __base_state.__current_ < __state.__current_)
__base_state = std::move(__state);
if (__base_state.__current_ == __last) {
- __copy_to_submatches(__base_state.__sub_matches_.get(), __submatch_count, __sub_matches);
+ __copy_to_submatches(__base_state.__sub_matches_.get(), __gexec_state.__submatch_count_, __sub_matches);
return {true, __base_state.__current_};
}
__found_match = true;
@@ -865,11 +864,11 @@ class __interpreter {
}
if (!__found_match)
return {false, {}};
- __copy_to_submatches(__base_state.__sub_matches_.get(), __submatch_count, __sub_matches);
+ __copy_to_submatches(__base_state.__sub_matches_.get(), __gexec_state.__submatch_count_, __sub_matches);
return {true, __base_state.__current_};
} else {
if (__base_state_matched) {
- __copy_to_submatches(__base_state.__sub_matches_.get(), __submatch_count, __sub_matches);
+ __copy_to_submatches(__base_state.__sub_matches_.get(), __gexec_state.__submatch_count_, __sub_matches);
return {true, __base_state.__current_};
}
while (!__gexec_state.__states_.empty()) {
@@ -878,7 +877,7 @@ class __interpreter {
__base_state = std::move(__gexec_state.__states_.back());
__gexec_state.__states_.pop_back();
if (auto [__success, __counter] = __base_state.__execute(__first, __last, __gexec_state); __success) {
- __copy_to_submatches(__base_state.__sub_matches_.get(), __submatch_count, __sub_matches);
+ __copy_to_submatches(__base_state.__sub_matches_.get(), __gexec_state.__submatch_count_, __sub_matches);
return {true, __base_state.__current_};
} else {
__gcounter += __counter;
@@ -888,38 +887,49 @@ class __interpreter {
}
}
+ pair<bool, const _CharT*> __execute_match(
+ regex_constants::match_flag_type __flags,
+ const _CharT* __first,
+ const _CharT* __last,
+ size_t __submatch_count,
+ vector<sub_match<const _CharT*>>& __sub_matches) const {
+ __global_execution_state __gexec_state{{}, *this, __submatch_count, __flags};
+ return __execute(__gexec_state, __first, __last, __sub_matches);
+ }
+
__search_result<_CharT> __execute_search(
- const _CharT* __first, const _CharT* __last, regex_constants::match_flag_type __flags, size_t __marked_count) {
+ const _CharT* __first,
+ const _CharT* __last,
+ regex_constants::match_flag_type __flags,
+ size_t __marked_count) const {
sub_match<const _CharT*> __unmatched;
__unmatched.first = __last;
__unmatched.second = __last;
__unmatched.matched = false;
+ __global_execution_state __gexec_state{
+ {},
+ *this,
+ __marked_count,
+ __flags | ((__flags & regex_constants::__no_update_pos) ? regex_constants::match_flag_type()
+ : regex_constants::__at_first)};
vector<sub_match<const _CharT*>> __sub_matches;
- if (auto [__success, __last_val] = __execute(
- __flags | ((__flags & regex_constants::__no_update_pos) ? regex_constants::match_flag_type()
- : regex_constants::__at_first),
- __first,
- __last,
- __marked_count,
- __sub_matches);
- __success) {
+ if (auto [__success, __last_val] = __execute(__gexec_state, __first, __last, __sub_matches); __success) {
return {__first, __last_val, std::move(__sub_matches)};
}
if (__first == __last || (__flags & regex_constants::match_continuous))
return {};
- __flags |= regex_constants::match_prev_avail;
+ __gexec_state.__flags_ = __flags | regex_constants::match_prev_avail;
for (++__first; __first != __last; ++__first) {
- if (auto [__success, __last_val] = __execute(__flags, __first, __last, __marked_count, __sub_matches);
- __success) {
+ if (auto [__success, __last_val] = __execute(__gexec_state, __first, __last, __sub_matches); __success) {
return {__first, __last_val, std::move(__sub_matches)};
}
}
- if (auto [__success, __last_val] = __execute(__flags, __first, __last, __marked_count, __sub_matches); __success) {
+ if (auto [__success, __last_val] = __execute(__gexec_state, __first, __last, __sub_matches); __success) {
return {__first, __last_val, std::move(__sub_matches)};
}
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 13492357a059d..6048744eeeae0 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -1288,7 +1288,7 @@ public:
: __regex_search_state<_CharT>(__s), __machine_(std::move(__machine)) {}
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __exec(__state<_CharT>& __state) const override {
- auto __res = __machine_.__execute(
+ auto __res = __machine_.__execute_match(
__state.__flags_ | (__state.__at_first_ ? regex_constants::__at_first : regex_constants::match_flag_type()),
__state.__first_,
__state.__last_,
diff --git a/libcxx/test/benchmarks/regex.bench.cpp b/libcxx/test/benchmarks/regex.bench.cpp
index 8b218843dedc1..75174a7e71706 100644
--- a/libcxx/test/benchmarks/regex.bench.cpp
+++ b/libcxx/test/benchmarks/regex.bench.cpp
@@ -48,4 +48,15 @@ static void BM_regex_run_almost_match(benchmark::State& state) {
}
BENCHMARK(BM_regex_run_almost_match);
+static void BM_regex_run_any_matcher(benchmark::State& state) {
+ std::regex r(".*");
+ std::string input;
+ input.append(1 << 16, 'a');
+
+ for (auto _ : state) {
+ std::regex_search(input, r);
+ }
+}
+BENCHMARK(BM_regex_run_any_matcher);
+
BENCHMARK_MAIN();
>From b7604c69c530c954e849dd3ab49437513610be4a Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 31 Mar 2026 04:04:02 +0200
Subject: [PATCH 13/21] Add preserve_none
---
libcxx/include/__regex/interpreter.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 9d5bf86bb7ca7..3dec7c9294e7c 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -418,6 +418,7 @@ struct __local_execution_state {
return __current_pos;
}
+ [[clang::preserve_none]]
pair<bool, size_t> __execute(const _CharT* __first, const _CharT* __last, __global_state& __gstate) {
const __interpreter_info<_CharT>* const __code = __gstate.__machine().data();
auto __current_pos = __current_pos_;
@@ -805,6 +806,7 @@ class __interpreter {
size_t size() const { return __machine_.size(); }
+ [[clang::preserve_none]]
pair<bool, const _CharT*>
__execute(__global_execution_state<_CharT, _Traits>& __gexec_state,
const _CharT* __first,
>From ce44d8eab490f0fdcff84506dc7be76c160b3e17 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 6 Apr 2026 14:26:47 +0200
Subject: [PATCH 14/21] Make state handling more efficient
---
libcxx/include/__regex/interpreter.h | 246 ++++++++++++++++-----------
libcxx/include/regex | 4 +-
2 files changed, 153 insertions(+), 97 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 3dec7c9294e7c..5e081f2e99662 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -163,10 +163,14 @@ template <class _CharT, class _Traits>
struct __local_execution_state {
using __global_state = __global_execution_state<_CharT, _Traits>;
+ pair<const _CharT*, const _CharT*>& __get_submatch(size_t __n) {
+ return *reinterpret_cast<pair<const _CharT*, const _CharT*>*>(
+ reinterpret_cast<char*>(this) - sizeof(pair<const _CharT*, const _CharT*>) * (__n + 1));
+ }
+
const _CharT* __current_;
- unique_ptr<pair<const _CharT*, const _CharT*>[]> __sub_matches_;
size_t __current_pos_;
- unique_ptr<__loop_value<_CharT>[]> __loop_values_;
+ __loop_value<_CharT> __loop_values_[];
static pair<size_t, size_t>
__read_uleb_impl(_LIBCPP_NOESCAPE const __interpreter_info<_CharT>* __machine, size_t __current_pos) {
@@ -192,16 +196,6 @@ struct __local_execution_state {
return __val;
}
- void __copy_to(const _CharT* const __current, vector<__local_execution_state>& __vec, __global_state& __gstate) {
- auto __loop_value_count = __gstate.__machine_.__initial_loop_values_.size();
- auto __loop_values_copy = std::make_unique_for_overwrite<__loop_value<_CharT>[]>(__loop_value_count);
- std::copy_n(__loop_values_.get(), __loop_value_count, __loop_values_copy.get());
- auto __sub_matches =
- std::make_unique_for_overwrite<pair<const _CharT*, const _CharT*>[]>(__gstate.__submatch_count_);
- std::copy_n(__sub_matches_.get(), __gstate.__submatch_count_, __sub_matches.get());
- __vec.emplace_back(__current, std::move(__sub_matches), __current_pos_, std::move(__loop_values_copy));
- }
-
static bool __is_word_boundary(
const _CharT* __first, const _CharT* __last, const _CharT* const __current, __global_state& __gstate) {
auto __is_word_char = [&](char __c) {
@@ -354,40 +348,42 @@ struct __local_execution_state {
return {__found, false, __current_pos};
}
- pair<bool, size_t> __exec_lookahead(
- const _CharT* const __first,
- const _CharT* const __last,
- const __global_state& __gstate,
- const __interpreter_info<_CharT>* const __code,
- size_t __current_pos,
- bool __is_positive) {
- auto __jump_offset = __read_uleb(__code, __current_pos);
- auto __submatch_count = __read_uleb(__code, __current_pos);
- auto __submatch_base = __read_uleb(__code, __current_pos);
- auto __loop_count = __read_uleb(__code, __current_pos);
-
- auto __initial_loop_values = std::make_unique_for_overwrite<__loop_value<_CharT>[]>(__loop_count);
-
- for (size_t __i = 0; __i != __loop_count; ++__i)
- __initial_loop_values[__i] = __read_uleb(__code, __current_pos);
-
- __global_state __gexec_state{{}, __gstate.__machine_, __submatch_count, __gstate.__flags_};
- __gexec_state.__flags_ &= ~regex_constants::__full_match;
- auto& __s = __gexec_state.__states_.emplace_back();
- if (__loop_count > 0)
- __s.__sub_matches_ = std::make_unique<pair<const _CharT*, const _CharT*>[]>(__submatch_count);
- __s.__current_ = __current_;
- __s.__loop_values_ = std::move(__initial_loop_values);
- __s.__current_pos_ = __current_pos;
- if (__gexec_state.__execute(__first, __last) != __is_positive)
- return {false, __current_pos};
- if (__is_positive) {
- auto& __matched_state = __gexec_state.__states_.back();
- std::copy_n(__matched_state.__sub_matches_.get(), __submatch_count, __sub_matches_.get() + __submatch_base);
- }
- __current_pos += __jump_offset;
- return {true, __current_pos};
+ /*
+pair<bool, size_t> __exec_lookahead(
+ const _CharT* const __first,
+ const _CharT* const __last,
+ const __global_state& __gstate,
+ const __interpreter_info<_CharT>* const __code,
+ size_t __current_pos,
+ bool __is_positive) {
+ auto __jump_offset = __read_uleb(__code, __current_pos);
+ auto __submatch_count = __read_uleb(__code, __current_pos);
+ auto __submatch_base = __read_uleb(__code, __current_pos);
+ auto __loop_count = __read_uleb(__code, __current_pos);
+
+ auto __initial_loop_values = std::make_unique_for_overwrite<__loop_value<_CharT>[]>(__loop_count);
+
+ for (size_t __i = 0; __i != __loop_count; ++__i)
+ __initial_loop_values[__i] = __read_uleb(__code, __current_pos);
+
+ __global_state __gexec_state{{}, __gstate.__machine_, __submatch_count, __gstate.__flags_};
+ __gexec_state.__flags_ &= ~regex_constants::__full_match;
+ auto& __s = __gexec_state.__states_.emplace_back();
+ if (__loop_count > 0)
+ __s.__sub_matches_ = std::make_unique<pair<const _CharT*, const _CharT*>[]>(__submatch_count);
+ __s.__current_ = __current_;
+ __s.__loop_values_ = std::move(__initial_loop_values);
+ __s.__current_pos_ = __current_pos;
+ if (__gexec_state.__execute(__first, __last) != __is_positive)
+ return {false, __current_pos};
+ if (__is_positive) {
+ auto& __matched_state = __gexec_state.__states_.back();
+ std::copy_n(__matched_state.__sub_matches_.get(), __submatch_count, __get_submatch(__submatch_base));
}
+ __current_pos += __jump_offset;
+ return {true, __current_pos};
+}
+ */
size_t __exec_branch_n_to_m_matcher(
__global_state& __gstate,
@@ -406,7 +402,8 @@ struct __local_execution_state {
if (__loop_values_[__loop_index].__ptr_ != __current && __loop_values_[__loop_index + 2].__int_ > 0) {
--__loop_values_[__loop_index + 2].__int_;
__loop_values_[__loop_index] = __current;
- __copy_to(__current, __gstate.__states_, __gstate);
+ __gstate.__states_.push(this);
+ __gstate.__states_.back().__current_ = __current;
if (!__is_greedy) {
__gstate.__states_.back().__current_pos_ = __again_pos;
} else {
@@ -487,7 +484,8 @@ struct __local_execution_state {
case __branch_alternative: {
auto __offset = __read_uleb(__code, __current_pos);
- __copy_to(__current, __gstate.__states_, __gstate);
+ __gstate.__states_.push(this);
+ __gstate.__states_.back().__current_ = __current;
__gstate.__states_.back().__current_pos_ = __current_pos + __offset;
break;
}
@@ -504,7 +502,7 @@ struct __local_execution_state {
} break;
case __match_backref: {
- auto& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
+ auto& __match = __get_submatch(__read_uleb(__code, __current_pos) - 1);
if (__match.first == nullptr)
return {false, __counter};
@@ -516,7 +514,7 @@ struct __local_execution_state {
} break;
case __match_icase_backref: {
- auto& __match = __sub_matches_[__read_uleb(__code, __current_pos) - 1];
+ auto& __match = __get_submatch(__read_uleb(__code, __current_pos) - 1);
if (__match.first == nullptr)
return {false, __counter};
@@ -551,12 +549,12 @@ struct __local_execution_state {
case __marked_subexpression_begin: {
auto __match = __read_uleb(__code, __current_pos);
- __sub_matches_[__match].first = __current;
+ __get_submatch(__match).first = __current;
} break;
case __marked_subexpression_end: {
auto __match = __read_uleb(__code, __current_pos);
- __sub_matches_[__match].second = __current;
+ __get_submatch(__match).second = __current;
} break;
case __match_word_boundary: {
@@ -571,13 +569,13 @@ struct __local_execution_state {
case __negative_lookahead:
case __positive_lookahead: {
- if (auto __result =
- __exec_lookahead(__first, __last, __gstate, __code, __current_pos, (__st == __positive_lookahead));
- __result.first)
- __current_pos = __result.second;
- else
- return {false, __counter};
- } break;
+ // if (auto __result =
+ // __exec_lookahead(__first, __last, __gstate, __code, __current_pos, (__st == __positive_lookahead));
+ // __result.first)
+ // __current_pos = __result.second;
+ // else
+ // return {false, __counter};
+ } // break;
default:
std::__libcpp_unreachable();
@@ -586,12 +584,63 @@ struct __local_execution_state {
}
};
+template <class _CharT, class _Traits>
+class __local_execution_state_stack {
+ char* __data_begin_ = nullptr;
+ size_t __base_offset_;
+ size_t __object_size_;
+ size_t __size_ = 0;
+ size_t __capacity_ = 0;
+
+public:
+ using value_type = __local_execution_state<_CharT, _Traits>;
+
+ static_assert(__is_trivially_copyable(value_type) && __is_trivially_destructible(value_type));
+
+ __local_execution_state_stack(size_t __loop_value_count, size_t __submatch_count)
+ : __base_offset_(__submatch_count * sizeof(pair<const _CharT*, const _CharT*>)),
+ __object_size_(__base_offset_ + sizeof(value_type) + __loop_value_count * sizeof(__loop_value<_CharT>)) {}
+
+ __local_execution_state_stack(const __local_execution_state_stack&) = delete;
+ __local_execution_state_stack& operator=(const __local_execution_state_stack&) = delete;
+ ~__local_execution_state_stack() { __builtin_free(__data_begin_); }
+
+ bool empty() const { return __size_ == 0; }
+
+ value_type& back() {
+ return *reinterpret_cast<value_type*>(__data_begin_ + __object_size_ * (__size_ - 1) + __base_offset_);
+ }
+
+ void push(const value_type* __val) {
+ if (__size_ == __capacity_) [[unlikely]] {
+ auto __new_cap = 2 * __capacity_ + 1;
+ if (auto __new_ptr = __builtin_realloc(__data_begin_, __new_cap * __object_size_)) {
+ __data_begin_ = static_cast<char*>(__new_ptr);
+ __capacity_ = __new_cap;
+ } else {
+ std::__throw_bad_alloc();
+ }
+ }
+ __builtin_memcpy((__data_begin_ + __object_size_ * __size_),
+ reinterpret_cast<const char*>(__val) - __base_offset_,
+ __object_size_);
+ ++__size_;
+ }
+
+ void pop(value_type* __tmp) {
+ _LIBCPP_ASSERT_INTERNAL(__size_ != 0, "Trying to pop from empty stack!");
+ --__size_;
+ __builtin_memcpy(
+ reinterpret_cast<char*>(__tmp) - __base_offset_, __data_begin_ + __object_size_ * __size_, __object_size_);
+ }
+};
+
template <class _CharT, class _Traits>
class __interpreter;
template <class _CharT, class _Traits>
struct __global_execution_state {
- vector<__local_execution_state<_CharT, _Traits>> __states_;
+ __local_execution_state_stack<_CharT, _Traits> __states_;
const __interpreter<_CharT, _Traits>& __machine_;
size_t __submatch_count_;
regex_constants::match_flag_type __flags_;
@@ -806,7 +855,7 @@ class __interpreter {
size_t size() const { return __machine_.size(); }
- [[clang::preserve_none]]
+ // [[clang::preserve_none]]
pair<bool, const _CharT*>
__execute(__global_execution_state<_CharT, _Traits>& __gexec_state,
const _CharT* __first,
@@ -818,7 +867,10 @@ class __interpreter {
[&](pair<const _CharT*, const _CharT*>* __from, size_t __count, vector<sub_match<const _CharT*>>& __to) {
__to.clear();
std::transform(
- __from, __from + __count, std::back_inserter(__to), [&](pair<const _CharT*, const _CharT*> __v) {
+ std::make_reverse_iterator(__from + __count),
+ std::make_reverse_iterator(__from),
+ std::back_inserter(__to),
+ [&](pair<const _CharT*, const _CharT*> __v) {
sub_match<const _CharT*> __ret;
__ret.first = __v.first ? __v.first : __last;
__ret.second = __v.first ? __v.second : __last;
@@ -827,60 +879,63 @@ class __interpreter {
});
};
- __local_state __base_state{
- .__current_ = __first,
- .__sub_matches_ = __gexec_state.__submatch_count_
- ? std::make_unique<pair<const _CharT*, const _CharT*>[]>(__gexec_state.__submatch_count_)
- : nullptr,
- .__current_pos_ = 0,
- .__loop_values_ = __initial_loop_values_.empty()
- ? nullptr
- : std::make_unique_for_overwrite<__loop_value<_CharT>[]>(__initial_loop_values_.size()),
- };
- if (!__initial_loop_values_.empty())
- std::copy(__initial_loop_values_.begin(), __initial_loop_values_.end(), __base_state.__loop_values_.get());
+ const auto __sizeof_submatches = sizeof(pair<const _CharT*, const _CharT*>) * __gexec_state.__submatch_count_;
+ const auto __sizeof_loop_values = sizeof(__loop_value<_CharT>) * __initial_loop_values_.size();
+ const auto __state_size = __sizeof_submatches + sizeof(__local_state) + __sizeof_loop_values;
+
+ auto* __base_state_start = static_cast<char*>(__builtin_alloca(2 * __state_size));
+ auto* __base_state_submatches = reinterpret_cast<pair<const _CharT*, const _CharT*>*>(__base_state_start);
+ auto* __base_state = reinterpret_cast<__local_state*>(__base_state_start + __sizeof_submatches);
+ auto* __tmp_state_start = __base_state_start + __state_size;
+ auto* __tmp_state = reinterpret_cast<__local_state*>(__tmp_state_start + __sizeof_submatches);
+
+ std::uninitialized_fill_n(
+ __base_state_submatches, __gexec_state.__submatch_count_, pair<const _CharT*, const _CharT*>{nullptr, nullptr});
+ std::__construct_at(__base_state, __first, 0);
+ std::uninitialized_copy(
+ __initial_loop_values_.begin(),
+ __initial_loop_values_.end(),
+ reinterpret_cast<__loop_value<_CharT>*>(__base_state_start + __sizeof_submatches + sizeof(__local_state)));
- auto [__base_state_matched, __gcounter] = __base_state.__execute(__first, __last, __gexec_state);
+ auto [__base_state_matched, __gcounter] = __base_state->__execute(__first, __last, __gexec_state);
size_t __length = __last - __first + 1;
if (__gexec_state.__machine_.__find_longest_) {
if (!__base_state_matched)
- __base_state.__current_ = __first;
+ __base_state->__current_ = __first;
bool __found_match = __base_state_matched;
while (!__gexec_state.__states_.empty()) {
if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
std::__throw_regex_error<regex_constants::error_complexity>();
- auto __state = std::move(__gexec_state.__states_.back());
- __gexec_state.__states_.pop_back();
- auto [__success, __counter] = __state.__execute(__first, __last, __gexec_state);
+ __gexec_state.__states_.pop(__tmp_state);
+ auto [__success, __counter] = __tmp_state->__execute(__first, __last, __gexec_state);
__gcounter += __counter;
if (__success) {
- if (!__found_match || __base_state.__current_ < __state.__current_)
- __base_state = std::move(__state);
- if (__base_state.__current_ == __last) {
- __copy_to_submatches(__base_state.__sub_matches_.get(), __gexec_state.__submatch_count_, __sub_matches);
- return {true, __base_state.__current_};
+ if (!__found_match || __base_state->__current_ < __tmp_state->__current_)
+ __builtin_memcpy(__base_state_start, __tmp_state_start, __state_size);
+ if (__base_state->__current_ == __last) {
+ __copy_to_submatches(__base_state_submatches, __gexec_state.__submatch_count_, __sub_matches);
+ return {true, __base_state->__current_};
}
__found_match = true;
}
}
if (!__found_match)
return {false, {}};
- __copy_to_submatches(__base_state.__sub_matches_.get(), __gexec_state.__submatch_count_, __sub_matches);
- return {true, __base_state.__current_};
+ __copy_to_submatches(__base_state_submatches, __gexec_state.__submatch_count_, __sub_matches);
+ return {true, __base_state->__current_};
} else {
if (__base_state_matched) {
- __copy_to_submatches(__base_state.__sub_matches_.get(), __gexec_state.__submatch_count_, __sub_matches);
- return {true, __base_state.__current_};
+ __copy_to_submatches(__base_state_submatches, __gexec_state.__submatch_count_, __sub_matches);
+ return {true, __base_state->__current_};
}
while (!__gexec_state.__states_.empty()) {
if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
std::__throw_regex_error<regex_constants::error_complexity>();
- __base_state = std::move(__gexec_state.__states_.back());
- __gexec_state.__states_.pop_back();
- if (auto [__success, __counter] = __base_state.__execute(__first, __last, __gexec_state); __success) {
- __copy_to_submatches(__base_state.__sub_matches_.get(), __gexec_state.__submatch_count_, __sub_matches);
- return {true, __base_state.__current_};
+ __gexec_state.__states_.pop(__base_state);
+ if (auto [__success, __counter] = __base_state->__execute(__first, __last, __gexec_state); __success) {
+ __copy_to_submatches(__base_state_submatches, __gexec_state.__submatch_count_, __sub_matches);
+ return {true, __base_state->__current_};
} else {
__gcounter += __counter;
}
@@ -895,7 +950,8 @@ class __interpreter {
const _CharT* __last,
size_t __submatch_count,
vector<sub_match<const _CharT*>>& __sub_matches) const {
- __global_execution_state __gexec_state{{}, *this, __submatch_count, __flags};
+ __global_execution_state<_CharT, _Traits> __gexec_state{
+ {__initial_loop_values_.size(), __sub_matches.size()}, *this, __submatch_count, __flags};
return __execute(__gexec_state, __first, __last, __sub_matches);
}
@@ -909,8 +965,8 @@ class __interpreter {
__unmatched.second = __last;
__unmatched.matched = false;
- __global_execution_state __gexec_state{
- {},
+ __global_execution_state<_CharT, _Traits> __gexec_state{
+ {__initial_loop_values_.size(), __marked_count},
*this,
__marked_count,
__flags | ((__flags & regex_constants::__no_update_pos) ? regex_constants::match_flag_type()
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 6048744eeeae0..c5bad522a16f0 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -1307,8 +1307,8 @@ public:
}
};
-static_assert(sizeof(__regex::__global_execution_state<char, regex_traits<char>>) == 48);
-static_assert(sizeof(__regex::__local_execution_state<char, regex_traits<char>>) == 32);
+static_assert(sizeof(__regex::__global_execution_state<char, regex_traits<char>>) == 64);
+static_assert(sizeof(__regex::__local_execution_state<char, regex_traits<char>>) == 16);
template <class _CharT, class _Traits = regex_traits<_CharT> >
class basic_regex;
>From 609b0eca3cad91be202462c3eacbca49ccef62d5 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 7 Apr 2026 02:44:16 +0200
Subject: [PATCH 15/21] Make most bracket expressions faster
---
libcxx/include/__regex/interpreter.h | 69 ++++++++++++++++++++++++++
libcxx/test/benchmarks/regex.bench.cpp | 23 +++++++++
2 files changed, 92 insertions(+)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 5e081f2e99662..fd4304bc21931 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -85,6 +85,7 @@ enum class __state : uint8_t {
__match_icase_backref,
__match_character_list,
__match_no_character_list,
+ __match_simple_character_list,
__marked_subexpression_begin,
__marked_subexpression_end,
__branch_n_to_m_matcher,
@@ -100,6 +101,7 @@ enum class __state : uint8_t {
template <class _CharT>
union __interpreter_info {
+ __interpreter_info() = default;
__interpreter_info(__state __st) : __state_(__st) {}
__interpreter_info(_CharT __c) : __char_(__c) {}
__interpreter_info(uint8_t __int) : __int_(__int) {}
@@ -531,6 +533,20 @@ pair<bool, size_t> __exec_lookahead(
__current += __len;
} break;
+ case __match_simple_character_list: {
+ if (__current == __last)
+ return {false, __counter};
+
+ using _SetT = unsigned _BitInt(256);
+
+ _SetT __set;
+ __builtin_memcpy(&__set, __code + __current_pos, sizeof(_SetT));
+ __current_pos += sizeof(_SetT);
+ if (!(__set & (_SetT(1) << *__current)))
+ return {false, __counter};
+ ++__current;
+ } break;
+
case __match_character_list:
case __match_no_character_list: {
if (__current == __last)
@@ -801,6 +817,59 @@ class __interpreter {
}
void __push_bracket_expr(bool __negate, const __bracket_expr<_CharT, _Traits>& __expr) {
+ bool __has_digraph_range = false;
+ for (size_t __i = 1; __i < __expr.__ranges_.size(); __i += 2) {
+ if (__expr.__ranges_[__i] != '\0')
+ __has_digraph_range = true;
+ }
+
+ if constexpr (__is_same(_CharT, char)) {
+ if (!__has_digraph_range && __expr.__digraphs_.empty() && __expr.__equivalences_.empty()) {
+ using _SetT = unsigned _BitInt(256);
+
+ _SetT __set = 0;
+
+ if (__expr.__neg_mask_ != 0 || !__expr.__neg_chars_.empty()) {
+ for (size_t __i = 0; __i != 256; ++__i) {
+ if (__traits_.isctype(char(__i), __expr.__neg_mask_))
+ __set |= _SetT(1) << __i;
+ }
+ for (auto __c : __expr.__neg_chars_)
+ __set |= _SetT(1) << __c;
+ __set = ~__set;
+ }
+
+ for (auto __c : __expr.__chars_)
+ __set |= _SetT(1) << __c;
+
+ for (size_t __i = 0; __i != __expr.__ranges_.size(); __i += 4) {
+ for (char __j = __expr.__ranges_[__i]; __j != __expr.__ranges_[__i + 2]; ++__j)
+ __set |= _SetT(1) << __j;
+ }
+
+ if (__expr.__mask_ != 0) {
+ for (size_t __i = 0; __i != 256; ++__i) {
+ if (__traits_.isctype(char(__i), __expr.__mask_))
+ __set |= _SetT(1) << __i;
+ }
+ }
+
+ if (__negate)
+ __set = ~__set;
+
+ if (__builtin_popcountg(__set) == 1) {
+ __push_char_matcher(__builtin_ctzg(__set));
+ return;
+ }
+
+ push_back(__state::__match_simple_character_list);
+ __interpreter_info<_CharT> __buffer[sizeof(_SetT)];
+ __builtin_memcpy(__buffer, &__set, sizeof(_SetT));
+ append_range(__buffer);
+ return;
+ }
+ }
+
push_back(__negate ? __state::__match_no_character_list : __state::__match_character_list);
_CharT __buffer[std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1))];
diff --git a/libcxx/test/benchmarks/regex.bench.cpp b/libcxx/test/benchmarks/regex.bench.cpp
index 75174a7e71706..725c0ec50a77f 100644
--- a/libcxx/test/benchmarks/regex.bench.cpp
+++ b/libcxx/test/benchmarks/regex.bench.cpp
@@ -59,4 +59,27 @@ static void BM_regex_run_any_matcher(benchmark::State& state) {
}
BENCHMARK(BM_regex_run_any_matcher);
+static void BM_regex_run_alphabet_matcher(benchmark::State& state) {
+ std::regex r("[a-zA-Z]*");
+ std::string input;
+ input.append(1 << 16, 'a');
+
+ for (auto _ : state) {
+ std::regex_search(input, r);
+ }
+}
+BENCHMARK(BM_regex_run_alphabet_matcher);
+
+static void BM_regex_run_mail_matcher(benchmark::State& state) {
+ std::regex r(
+ R"regex((?:(?:[^<>()\[\].,;:\s@"]+(?:\.[^<>()\[\].,;:\s@"]+)*)|".+")@(?:(?:[^<>()\[\].,;:\s@"]+\.)+[^<>()\[\].,;:\s@"]{2,}))regex");
+ std::string input;
+ input.append(1 << 8, 'a');
+
+ for (auto _ : state) {
+ std::regex_search(input, r);
+ }
+}
+BENCHMARK(BM_regex_run_mail_matcher);
+
BENCHMARK_MAIN();
>From b30f7acede2f18f63656a7a045ccbfb53831f2f5 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 9 Apr 2026 07:02:25 +0200
Subject: [PATCH 16/21] Make alternatives deterministic if they have a disjunct
set of matching characters
---
libcxx/include/__regex/interpreter.h | 219 +++++++++++++++++++++------
1 file changed, 169 insertions(+), 50 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index fd4304bc21931..e7723ce92bb6a 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -71,12 +71,17 @@ struct __state {
};
namespace __regex {
+using _MatchingSetT = unsigned _BitInt(256);
+using _MatchingSetWithEndT = unsigned _BitInt(257);
+
enum class __state : uint8_t {
+ // Anchors
__start_anchor,
__end_anchor,
__multiline_start_anchor,
__multiline_end_anchor,
- __branch_alternative,
+
+ // Consuming matches
__match_any,
__match_any_except_newline,
__match_char,
@@ -86,16 +91,29 @@ enum class __state : uint8_t {
__match_character_list,
__match_no_character_list,
__match_simple_character_list,
+
+ // Marked subexpressions
__marked_subexpression_begin,
__marked_subexpression_end,
- __branch_n_to_m_matcher,
- __branch_nongreedy_n_to_m_matcher,
- __match_n_to_m_times,
+
+ // Non-consuming matches
__match_word_boundary,
__match_no_word_boundary,
+
+ // Lookahead
__positive_lookahead,
__negative_lookahead,
+
+ // Jumps
__relative_jump,
+ __conditional_jump,
+
+ // Branches
+ __branch_n_to_m_matcher,
+ __branch_nongreedy_n_to_m_matcher,
+ __branch_alternative,
+
+ // End state
__end_state,
};
@@ -111,11 +129,37 @@ union __interpreter_info {
__state __state_;
_CharT __char_;
- uint8_t __int_;
+ unsigned _BitInt(8) __int_;
};
static_assert(sizeof(__interpreter_info<char>) == 1);
+template <class _CharT>
+pair<size_t, size_t>
+__read_uleb_impl(_LIBCPP_NOESCAPE const __interpreter_info<_CharT>* __machine, size_t __current_pos) {
+ size_t __result = 0;
+ size_t __shift = 0;
+
+ uint8_t __byte;
+ do {
+ __byte = __machine[__current_pos++].__int_;
+ __result |= (__byte & 0x7f) << __shift;
+ __shift += 7;
+ } while (__byte & 0x80);
+ return {__result, __current_pos};
+}
+
+template <class _CharT>
+size_t __read_uleb(const __interpreter_info<_CharT>* __machine, size_t& __current_pos) {
+ auto __val = __machine[__current_pos++].__int_;
+ if (__val & 0x80) {
+ auto __res = __read_uleb_impl(__machine, __current_pos);
+ __current_pos = __res.second;
+ return __res.first;
+ }
+ return __val;
+}
+
template <class _CharT, class _Traits>
struct __bracket_expr {
vector<_CharT> __chars_;
@@ -174,30 +218,6 @@ struct __local_execution_state {
size_t __current_pos_;
__loop_value<_CharT> __loop_values_[];
- static pair<size_t, size_t>
- __read_uleb_impl(_LIBCPP_NOESCAPE const __interpreter_info<_CharT>* __machine, size_t __current_pos) {
- size_t __result = 0;
- size_t __shift = 0;
-
- uint8_t __byte;
- do {
- __byte = __machine[__current_pos++].__int_;
- __result |= (__byte & 0x7f) << __shift;
- __shift += 7;
- } while (__byte & 0x80);
- return {__result, __current_pos};
- }
-
- static size_t __read_uleb(const __interpreter_info<_CharT>* __machine, size_t& __current_pos) {
- auto __val = __machine[__current_pos++].__int_;
- if (__val & 0x80) {
- auto __res = __read_uleb_impl(__machine, __current_pos);
- __current_pos = __res.second;
- return __res.first;
- }
- return __val;
- }
-
static bool __is_word_boundary(
const _CharT* __first, const _CharT* __last, const _CharT* const __current, __global_state& __gstate) {
auto __is_word_char = [&](char __c) {
@@ -489,13 +509,22 @@ pair<bool, size_t> __exec_lookahead(
__gstate.__states_.push(this);
__gstate.__states_.back().__current_ = __current;
__gstate.__states_.back().__current_pos_ = __current_pos + __offset;
- break;
- }
+ } break;
case __relative_jump: {
__current_pos += __read_uleb(__code, __current_pos);
- break;
- }
+ } break;
+
+ case __conditional_jump: {
+ _MatchingSetT __set;
+ __builtin_memcpy(&__set, __code + __current_pos, sizeof(_MatchingSetT));
+ __current_pos += sizeof(_MatchingSetT);
+ auto __jump_offset = __read_uleb(__code, __current_pos);
+ if (__current == __last)
+ return {false, __counter};
+ if (!(__set & (_MatchingSetT(1) << *__current)))
+ __current_pos += __jump_offset;
+ } break;
case __branch_n_to_m_matcher:
case __branch_nongreedy_n_to_m_matcher: {
@@ -537,12 +566,10 @@ pair<bool, size_t> __exec_lookahead(
if (__current == __last)
return {false, __counter};
- using _SetT = unsigned _BitInt(256);
-
- _SetT __set;
- __builtin_memcpy(&__set, __code + __current_pos, sizeof(_SetT));
- __current_pos += sizeof(_SetT);
- if (!(__set & (_SetT(1) << *__current)))
+ _MatchingSetT __set;
+ __builtin_memcpy(&__set, __code + __current_pos, sizeof(_MatchingSetT));
+ __current_pos += sizeof(_MatchingSetT);
+ if (!(__set & (_MatchingSetT(1) << *__current)))
return {false, __counter};
++__current;
} break;
@@ -751,6 +778,85 @@ class __interpreter {
__write_uleb(__machine, __offset);
}
+ // This function returns the set of characters that _might_ match - there is no guarantee that any characters will
+ // actually be a match. This should never return an empty set, as that needs special handling.
+ inline _MatchingSetWithEndT __get_possibly_matching_characters(const __interpreter_info<char>* __m, size_t __pos) {
+ switch (__m[__pos++].__state_) {
+ using enum __state;
+ case __match_any_except_newline:
+ return ~(_MatchingSetT(1) << '\n');
+
+ case __match_char:
+ return _MatchingSetT(1) << __m[__pos].__char_;
+
+ case __match_simple_character_list: {
+ _MatchingSetT __set;
+ __builtin_memcpy(&__set, __m + __pos, sizeof(_MatchingSetT));
+ return __set;
+ }
+
+ case __marked_subexpression_begin:
+ case __marked_subexpression_end: {
+ __read_uleb(__m, __pos);
+ [[clang::musttail]] return __get_possibly_matching_characters(__m, __pos);
+ }
+
+ case __relative_jump: {
+ __pos += __read_uleb(__m, __pos);
+ [[clang::musttail]] return __get_possibly_matching_characters(__m, __pos);
+ }
+
+ case __branch_n_to_m_matcher:
+ case __branch_nongreedy_n_to_m_matcher: {
+ auto __loop_index = __read_uleb(__m, __pos);
+ __read_uleb(__m, __pos);
+ if (__initial_loop_values_[__loop_index + 1].__int_ == 0)
+ return ~_MatchingSetWithEndT();
+ [[clang::musttail]] return __get_possibly_matching_characters(__m, __pos);
+ }
+
+ case __start_anchor:
+ case __multiline_start_anchor:
+ case __match_word_boundary:
+ case __match_no_word_boundary: {
+ [[clang::musttail]] return __get_possibly_matching_characters(__m, __pos);
+ }
+
+ case __end_anchor:
+ case __multiline_end_anchor: {
+ return _MatchingSetWithEndT(1) << 256;
+ }
+
+ case __match_any: {
+ return ~_MatchingSetT();
+ }
+
+ case __conditional_jump: {
+ _MatchingSetT __set;
+ __builtin_memcpy(&__set, __m + __pos, sizeof(_MatchingSetT));
+ __pos += sizeof(_MatchingSetT);
+ auto __jump_offset = __read_uleb(__m, __pos);
+ return __set | __get_possibly_matching_characters(__m, __pos + __jump_offset);
+ }
+
+ // FIXME: Most of these should get some proper handling in here
+ case __match_icase_char:
+ case __branch_alternative:
+ case __match_character_list:
+ case __match_no_character_list:
+
+ // These can cause non-regular expressions, so claim anything could match
+ case __positive_lookahead:
+ case __negative_lookahead:
+ case __match_backref:
+ case __match_icase_backref:
+
+ // The end state actually matches anything
+ case __end_state:
+ return ~_MatchingSetWithEndT();
+ }
+ }
+
public:
__interpreter(const _Traits& __traits, bool __find_longest) : __traits_(__traits), __find_longest_(__find_longest) {
__machine_.reserve(16);
@@ -810,10 +916,25 @@ class __interpreter {
insert(__expr2_start, __buffer);
__expr2_start += __buffer.size();
__buffer.clear();
+
+ if constexpr (__is_same(_CharT, char)) {
+ if (__expr2_start != __machine_.size()) {
+ if (auto __expr1_set = __get_possibly_matching_characters(__machine_.data(), __expr1_start);
+ (__expr1_set & __get_possibly_matching_characters(__machine_.data(), __expr2_start)) == _MatchingSetT()) {
+ __buffer.push_back(__state::__conditional_jump);
+ __interpreter_info<_CharT> __sbuffer[sizeof(_MatchingSetT)];
+ __builtin_memcpy(__sbuffer, &__expr1_set, sizeof(_MatchingSetT));
+ __buffer.append_range(__sbuffer);
+ __write_uleb(__buffer, __expr2_start - __expr1_start);
+ insert(__expr1_start, __buffer);
+ return;
+ }
+ }
+ }
+
__buffer.push_back(__state::__branch_alternative);
__write_uleb(__buffer, __expr2_start - __expr1_start);
insert(__expr1_start, __buffer);
- __expr2_start += __buffer.size();
}
void __push_bracket_expr(bool __negate, const __bracket_expr<_CharT, _Traits>& __expr) {
@@ -825,32 +946,30 @@ class __interpreter {
if constexpr (__is_same(_CharT, char)) {
if (!__has_digraph_range && __expr.__digraphs_.empty() && __expr.__equivalences_.empty()) {
- using _SetT = unsigned _BitInt(256);
-
- _SetT __set = 0;
+ _MatchingSetT __set = 0;
if (__expr.__neg_mask_ != 0 || !__expr.__neg_chars_.empty()) {
for (size_t __i = 0; __i != 256; ++__i) {
if (__traits_.isctype(char(__i), __expr.__neg_mask_))
- __set |= _SetT(1) << __i;
+ __set |= _MatchingSetT(1) << __i;
}
for (auto __c : __expr.__neg_chars_)
- __set |= _SetT(1) << __c;
+ __set |= _MatchingSetT(1) << __c;
__set = ~__set;
}
for (auto __c : __expr.__chars_)
- __set |= _SetT(1) << __c;
+ __set |= _MatchingSetT(1) << __c;
for (size_t __i = 0; __i != __expr.__ranges_.size(); __i += 4) {
for (char __j = __expr.__ranges_[__i]; __j != __expr.__ranges_[__i + 2]; ++__j)
- __set |= _SetT(1) << __j;
+ __set |= _MatchingSetT(1) << __j;
}
if (__expr.__mask_ != 0) {
for (size_t __i = 0; __i != 256; ++__i) {
if (__traits_.isctype(char(__i), __expr.__mask_))
- __set |= _SetT(1) << __i;
+ __set |= _MatchingSetT(1) << __i;
}
}
@@ -863,8 +982,8 @@ class __interpreter {
}
push_back(__state::__match_simple_character_list);
- __interpreter_info<_CharT> __buffer[sizeof(_SetT)];
- __builtin_memcpy(__buffer, &__set, sizeof(_SetT));
+ __interpreter_info<_CharT> __buffer[sizeof(_MatchingSetT)];
+ __builtin_memcpy(__buffer, &__set, sizeof(_MatchingSetT));
append_range(__buffer);
return;
}
>From 57daa178359a8b0b5d3281a0a98e0c2073eb3d80 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 12 Apr 2026 15:19:20 +0200
Subject: [PATCH 17/21] Make loops determenistic
---
libcxx/include/__regex/basic_parser.h | 1 +
libcxx/include/__regex/ecma_parser.h | 1 +
libcxx/include/__regex/interpreter.h | 201 ++++++++++++++++++++-
libcxx/include/__type_traits/make_signed.h | 5 +
libcxx/test/benchmarks/regex.bench.cpp | 11 ++
5 files changed, 211 insertions(+), 8 deletions(-)
diff --git a/libcxx/include/__regex/basic_parser.h b/libcxx/include/__regex/basic_parser.h
index 9b8caeb688f4a..e9948015dcd84 100644
--- a/libcxx/include/__regex/basic_parser.h
+++ b/libcxx/include/__regex/basic_parser.h
@@ -229,6 +229,7 @@ class __parser {
void __parse_basic() {
__parse_basic_expr();
__machine_.__push_end_state();
+ __machine_.__optimize();
}
void __parse_grep() {
diff --git a/libcxx/include/__regex/ecma_parser.h b/libcxx/include/__regex/ecma_parser.h
index 6499349410a0e..06bb235caeeb9 100644
--- a/libcxx/include/__regex/ecma_parser.h
+++ b/libcxx/include/__regex/ecma_parser.h
@@ -294,6 +294,7 @@ class __parser {
if (__first_ != __last_)
std::__throw_regex_error<regex_constants::__re_err_parse>();
__machine_.__push_end_state();
+ __machine_.__optimize();
}
__interpreter<_CharT, _Traits> __extract_interpreter() { return std::move(__machine_); }
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index e7723ce92bb6a..88149795daef1 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -106,7 +106,8 @@ enum class __state : uint8_t {
// Jumps
__relative_jump,
- __conditional_jump,
+ __conditional_jump_forward,
+ __conditional_jump_backward,
// Branches
__branch_n_to_m_matcher,
@@ -515,11 +516,14 @@ pair<bool, size_t> __exec_lookahead(
__current_pos += __read_uleb(__code, __current_pos);
} break;
- case __conditional_jump: {
+ case __conditional_jump_forward:
+ case __conditional_jump_backward: {
_MatchingSetT __set;
__builtin_memcpy(&__set, __code + __current_pos, sizeof(_MatchingSetT));
__current_pos += sizeof(_MatchingSetT);
- auto __jump_offset = __read_uleb(__code, __current_pos);
+ auto __jump_offset = std::__to_signed_like(__read_uleb(__code, __current_pos));
+ if (__st == __conditional_jump_backward)
+ __jump_offset *= -1;
if (__current == __last)
return {false, __counter};
if (!(__set & (_MatchingSetT(1) << *__current)))
@@ -781,10 +785,11 @@ class __interpreter {
// This function returns the set of characters that _might_ match - there is no guarantee that any characters will
// actually be a match. This should never return an empty set, as that needs special handling.
inline _MatchingSetWithEndT __get_possibly_matching_characters(const __interpreter_info<char>* __m, size_t __pos) {
- switch (__m[__pos++].__state_) {
+ auto __state = __m[__pos++].__state_;
+ switch (__state) {
using enum __state;
case __match_any_except_newline:
- return ~(_MatchingSetT(1) << '\n');
+ return ~(_MatchingSetT(1) << '\n' | _MatchingSetWithEndT(1) << 256);
case __match_char:
return _MatchingSetT(1) << __m[__pos].__char_;
@@ -831,11 +836,14 @@ class __interpreter {
return ~_MatchingSetT();
}
- case __conditional_jump: {
+ case __conditional_jump_forward:
+ case __conditional_jump_backward: {
_MatchingSetT __set;
__builtin_memcpy(&__set, __m + __pos, sizeof(_MatchingSetT));
__pos += sizeof(_MatchingSetT);
- auto __jump_offset = __read_uleb(__m, __pos);
+ auto __jump_offset = std::__to_signed_like(__read_uleb(__m, __pos));
+ if (__state == __conditional_jump_backward)
+ __jump_offset *= -1;
return __set | __get_possibly_matching_characters(__m, __pos + __jump_offset);
}
@@ -862,6 +870,183 @@ class __interpreter {
__machine_.reserve(16);
}
+ void __fix_jumps(size_t __updated_instruction, ssize_t __offset) {
+ vector<pair<size_t, ssize_t>> __todo;
+ __todo.emplace_back(__updated_instruction, __offset);
+ auto __code = __machine_.data();
+
+ while (!__todo.empty()) {
+ size_t __pos = 0;
+ switch (__code[__pos++].__state_) {
+ using enum __state;
+ case __start_anchor:
+ case __end_anchor:
+ case __multiline_start_anchor:
+ case __multiline_end_anchor:
+ case __match_any:
+ case __match_any_except_newline:
+ case __match_word_boundary:
+ case __match_no_word_boundary:
+ break;
+
+ // Consuming matches
+ case __match_char:
+ case __match_icase_char:
+ ++__pos;
+ break;
+
+ case __match_simple_character_list:
+ __pos += sizeof(_MatchingSetT);
+ break;
+
+ case __match_backref:
+ case __match_icase_backref:
+ case __marked_subexpression_begin:
+ case __marked_subexpression_end:
+ __read_uleb(__code, __pos);
+ break;
+
+ case __match_character_list:
+ case __match_no_character_list: {
+ static constexpr auto __buffer_size =
+ std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1));
+ __pos += 2 * __buffer_size;
+ for (size_t __i = 0; __i != 6; ++__i)
+ __read_uleb(__code, __pos);
+ } break;
+
+ // Lookahead
+ case __positive_lookahead:
+ case __negative_lookahead:
+ std::__libcpp_unreachable();
+
+ // Jumps
+ case __relative_jump: {
+ auto __instr_start = __pos;
+ auto __jump_offset = __read_uleb(__code, __pos);
+ if (__pos < __todo.back().first && __pos + __jump_offset > __todo.back().first)
+ __jump_offset += __todo.back().second;
+ auto __num_size = __pos - __instr_start;
+ vector<__interpreter_info<_CharT>> __buffer;
+ __write_uleb(__buffer, __jump_offset);
+ if (__buffer.size() == __num_size) {
+ std::copy(__buffer.begin(), __buffer.end(), __code + __instr_start);
+ } else {
+
+ }
+ }
+
+ case __conditional_jump_forward:
+ case __conditional_jump_backward:
+
+ // Branches
+ case __branch_n_to_m_matcher:
+ case __branch_nongreedy_n_to_m_matcher:
+ case __branch_alternative:
+
+ // End state
+ case __end_state:
+ return;
+ }
+ }
+ }
+
+ void __optimize() {
+ auto __code = __machine_.data();
+ size_t __pos = 0;
+ while (__pos != __machine_.size()) {
+ switch (__code[__pos++].__state_) {
+ using enum __state;
+ case __start_anchor:
+ case __end_anchor:
+ case __multiline_start_anchor:
+ case __multiline_end_anchor:
+ case __match_any:
+ case __match_any_except_newline:
+ case __match_word_boundary:
+ case __match_no_word_boundary:
+ break;
+
+ case __match_char:
+ case __match_icase_char:
+ ++__pos;
+ break;
+
+ case __match_simple_character_list:
+ __pos += sizeof(_MatchingSetT);
+ break;
+
+ case __match_backref:
+ case __match_icase_backref:
+ case __marked_subexpression_begin:
+ case __marked_subexpression_end:
+ case __relative_jump:
+ __read_uleb(__code, __pos);
+ break;
+
+ case __match_character_list:
+ case __match_no_character_list: {
+ static constexpr auto __buffer_size =
+ std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1));
+ __pos += 2 * __buffer_size;
+ for (size_t __i = 0; __i != 6; ++__i)
+ __read_uleb(__code, __pos);
+ } break;
+
+ // Lookahead
+ case __positive_lookahead:
+ case __negative_lookahead:
+ return;
+
+ // Jumps
+ case __conditional_jump_forward:
+ case __conditional_jump_backward:
+ __pos += sizeof(_MatchingSetT);
+ __read_uleb(__code, __pos);
+ break;
+
+ // Branches
+ case __branch_n_to_m_matcher:
+ case __branch_nongreedy_n_to_m_matcher: {
+ auto __instr_start = __pos - 1;
+ auto __loop_index = __read_uleb(__code, __pos);
+ auto __again_pos_base = __pos;
+ auto __again_pos = __again_pos_base - __read_uleb(__code, __pos);
+ auto __instr_size = __pos - __instr_start;
+
+ if (__initial_loop_values_[__loop_index + 1].__int_ != 0 ||
+ __initial_loop_values_[__loop_index + 2].__int_ != numeric_limits<size_t>::max())
+ break;
+
+ if constexpr (__is_same(_CharT, char)) {
+ if (auto __expr1_set = __get_possibly_matching_characters(__machine_.data(), __again_pos);
+ (__expr1_set & __get_possibly_matching_characters(__machine_.data(), __pos)) == _MatchingSetT()) {
+ {
+ vector<__interpreter_info<_CharT>> __buffer;
+ __buffer.push_back(__state::__conditional_jump_backward);
+ __interpreter_info<_CharT> __sbuffer[sizeof(_MatchingSetT)];
+ __builtin_memcpy(__sbuffer, &__expr1_set, sizeof(_MatchingSetT));
+ __buffer.append_range(__sbuffer);
+ __write_uleb(__buffer, __instr_start - __again_pos);
+ __machine_.erase(__machine_.begin() + __instr_start, __machine_.begin() + __instr_start + __instr_size);
+ __machine_.insert(__machine_.begin() + __instr_start, __buffer.begin(), __buffer.end());
+ __fix_jumps(__instr_start, __buffer.size() - __instr_size);
+ }
+ [[clang::musttail]] return __optimize();
+ }
+ }
+ break;
+ }
+
+ case __branch_alternative:
+
+ // End state
+ case __end_state:
+ return;
+ }
+ }
+ }
+
void __push_any_matcher() { push_back(__state::__match_any); }
void __push_any_except_newline_matcher() { push_back(__state::__match_any_except_newline); }
void __push_end_state() { push_back(__state::__end_state); }
@@ -921,7 +1106,7 @@ class __interpreter {
if (__expr2_start != __machine_.size()) {
if (auto __expr1_set = __get_possibly_matching_characters(__machine_.data(), __expr1_start);
(__expr1_set & __get_possibly_matching_characters(__machine_.data(), __expr2_start)) == _MatchingSetT()) {
- __buffer.push_back(__state::__conditional_jump);
+ __buffer.push_back(__state::__conditional_jump_forward);
__interpreter_info<_CharT> __sbuffer[sizeof(_MatchingSetT)];
__builtin_memcpy(__sbuffer, &__expr1_set, sizeof(_MatchingSetT));
__buffer.append_range(__sbuffer);
diff --git a/libcxx/include/__type_traits/make_signed.h b/libcxx/include/__type_traits/make_signed.h
index dff23d880dc30..42a060084a259 100644
--- a/libcxx/include/__type_traits/make_signed.h
+++ b/libcxx/include/__type_traits/make_signed.h
@@ -74,6 +74,11 @@ struct _LIBCPP_NO_SPECIALIZATIONS make_signed {
using type _LIBCPP_NODEBUG = __make_signed_t<_Tp>;
};
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __make_signed_t<_Tp> __to_signed_like(_Tp __x) _NOEXCEPT {
+ return static_cast<__make_signed_t<_Tp> >(__x);
+}
+
#if _LIBCPP_STD_VER >= 14
template <class _Tp>
using make_signed_t = __make_signed_t<_Tp>;
diff --git a/libcxx/test/benchmarks/regex.bench.cpp b/libcxx/test/benchmarks/regex.bench.cpp
index 725c0ec50a77f..05b861171d9c5 100644
--- a/libcxx/test/benchmarks/regex.bench.cpp
+++ b/libcxx/test/benchmarks/regex.bench.cpp
@@ -70,6 +70,17 @@ static void BM_regex_run_alphabet_matcher(benchmark::State& state) {
}
BENCHMARK(BM_regex_run_alphabet_matcher);
+static void BM_regex_run_alternation_loop_matcher(benchmark::State& state) {
+ std::regex r("(a|b)*c");
+ std::string input;
+ input.append(1 << 8, 'a');
+
+ for (auto _ : state) {
+ std::regex_search(input, r);
+ }
+}
+BENCHMARK(BM_regex_run_alternation_loop_matcher);
+
static void BM_regex_run_mail_matcher(benchmark::State& state) {
std::regex r(
R"regex((?:(?:[^<>()\[\].,;:\s@"]+(?:\.[^<>()\[\].,;:\s@"]+)*)|".+")@(?:(?:[^<>()\[\].,;:\s@"]+\.)+[^<>()\[\].,;:\s@"]{2,}))regex");
>From 70903b1d8eb2556fe390f6220a20766e055026fe Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 20 Aug 2026 18:34:12 +0200
Subject: [PATCH 18/21] Fix stuff
---
libcxx/include/__regex/interpreter.h | 190 +--------------------------
1 file changed, 6 insertions(+), 184 deletions(-)
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 88149795daef1..b9c38fd6b9468 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -16,9 +16,10 @@
#include <__algorithm/transform.h>
#include <__config>
#include <__iterator/back_insert_iterator.h>
-#include <__locale>
+#include <__locale_dir/ctype_base.h>
#include <__regex/regex_error.h>
#include <__utility/pair.h>
+#include <__utility/scope_guard.h>
#include <__utility/to_underlying.h>
#include <__vector/vector.h>
#include <stack>
@@ -438,7 +439,6 @@ pair<bool, size_t> __exec_lookahead(
return __current_pos;
}
- [[clang::preserve_none]]
pair<bool, size_t> __execute(const _CharT* __first, const _CharT* __last, __global_state& __gstate) {
const __interpreter_info<_CharT>* const __code = __gstate.__machine().data();
auto __current_pos = __current_pos_;
@@ -803,12 +803,12 @@ class __interpreter {
case __marked_subexpression_begin:
case __marked_subexpression_end: {
__read_uleb(__m, __pos);
- [[clang::musttail]] return __get_possibly_matching_characters(__m, __pos);
+ return __get_possibly_matching_characters(__m, __pos);
}
case __relative_jump: {
__pos += __read_uleb(__m, __pos);
- [[clang::musttail]] return __get_possibly_matching_characters(__m, __pos);
+ return __get_possibly_matching_characters(__m, __pos);
}
case __branch_n_to_m_matcher:
@@ -817,14 +817,14 @@ class __interpreter {
__read_uleb(__m, __pos);
if (__initial_loop_values_[__loop_index + 1].__int_ == 0)
return ~_MatchingSetWithEndT();
- [[clang::musttail]] return __get_possibly_matching_characters(__m, __pos);
+ return __get_possibly_matching_characters(__m, __pos);
}
case __start_anchor:
case __multiline_start_anchor:
case __match_word_boundary:
case __match_no_word_boundary: {
- [[clang::musttail]] return __get_possibly_matching_characters(__m, __pos);
+ return __get_possibly_matching_characters(__m, __pos);
}
case __end_anchor:
@@ -870,183 +870,6 @@ class __interpreter {
__machine_.reserve(16);
}
- void __fix_jumps(size_t __updated_instruction, ssize_t __offset) {
- vector<pair<size_t, ssize_t>> __todo;
- __todo.emplace_back(__updated_instruction, __offset);
- auto __code = __machine_.data();
-
- while (!__todo.empty()) {
- size_t __pos = 0;
- switch (__code[__pos++].__state_) {
- using enum __state;
- case __start_anchor:
- case __end_anchor:
- case __multiline_start_anchor:
- case __multiline_end_anchor:
- case __match_any:
- case __match_any_except_newline:
- case __match_word_boundary:
- case __match_no_word_boundary:
- break;
-
- // Consuming matches
- case __match_char:
- case __match_icase_char:
- ++__pos;
- break;
-
- case __match_simple_character_list:
- __pos += sizeof(_MatchingSetT);
- break;
-
- case __match_backref:
- case __match_icase_backref:
- case __marked_subexpression_begin:
- case __marked_subexpression_end:
- __read_uleb(__code, __pos);
- break;
-
- case __match_character_list:
- case __match_no_character_list: {
- static constexpr auto __buffer_size =
- std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1));
- __pos += 2 * __buffer_size;
- for (size_t __i = 0; __i != 6; ++__i)
- __read_uleb(__code, __pos);
- } break;
-
- // Lookahead
- case __positive_lookahead:
- case __negative_lookahead:
- std::__libcpp_unreachable();
-
- // Jumps
- case __relative_jump: {
- auto __instr_start = __pos;
- auto __jump_offset = __read_uleb(__code, __pos);
- if (__pos < __todo.back().first && __pos + __jump_offset > __todo.back().first)
- __jump_offset += __todo.back().second;
- auto __num_size = __pos - __instr_start;
- vector<__interpreter_info<_CharT>> __buffer;
- __write_uleb(__buffer, __jump_offset);
- if (__buffer.size() == __num_size) {
- std::copy(__buffer.begin(), __buffer.end(), __code + __instr_start);
- } else {
-
- }
- }
-
- case __conditional_jump_forward:
- case __conditional_jump_backward:
-
- // Branches
- case __branch_n_to_m_matcher:
- case __branch_nongreedy_n_to_m_matcher:
- case __branch_alternative:
-
- // End state
- case __end_state:
- return;
- }
- }
- }
-
- void __optimize() {
- auto __code = __machine_.data();
- size_t __pos = 0;
- while (__pos != __machine_.size()) {
- switch (__code[__pos++].__state_) {
- using enum __state;
- case __start_anchor:
- case __end_anchor:
- case __multiline_start_anchor:
- case __multiline_end_anchor:
- case __match_any:
- case __match_any_except_newline:
- case __match_word_boundary:
- case __match_no_word_boundary:
- break;
-
- case __match_char:
- case __match_icase_char:
- ++__pos;
- break;
-
- case __match_simple_character_list:
- __pos += sizeof(_MatchingSetT);
- break;
-
- case __match_backref:
- case __match_icase_backref:
- case __marked_subexpression_begin:
- case __marked_subexpression_end:
- case __relative_jump:
- __read_uleb(__code, __pos);
- break;
-
- case __match_character_list:
- case __match_no_character_list: {
- static constexpr auto __buffer_size =
- std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1));
- __pos += 2 * __buffer_size;
- for (size_t __i = 0; __i != 6; ++__i)
- __read_uleb(__code, __pos);
- } break;
-
- // Lookahead
- case __positive_lookahead:
- case __negative_lookahead:
- return;
-
- // Jumps
- case __conditional_jump_forward:
- case __conditional_jump_backward:
- __pos += sizeof(_MatchingSetT);
- __read_uleb(__code, __pos);
- break;
-
- // Branches
- case __branch_n_to_m_matcher:
- case __branch_nongreedy_n_to_m_matcher: {
- auto __instr_start = __pos - 1;
- auto __loop_index = __read_uleb(__code, __pos);
- auto __again_pos_base = __pos;
- auto __again_pos = __again_pos_base - __read_uleb(__code, __pos);
- auto __instr_size = __pos - __instr_start;
-
- if (__initial_loop_values_[__loop_index + 1].__int_ != 0 ||
- __initial_loop_values_[__loop_index + 2].__int_ != numeric_limits<size_t>::max())
- break;
-
- if constexpr (__is_same(_CharT, char)) {
- if (auto __expr1_set = __get_possibly_matching_characters(__machine_.data(), __again_pos);
- (__expr1_set & __get_possibly_matching_characters(__machine_.data(), __pos)) == _MatchingSetT()) {
- {
- vector<__interpreter_info<_CharT>> __buffer;
- __buffer.push_back(__state::__conditional_jump_backward);
- __interpreter_info<_CharT> __sbuffer[sizeof(_MatchingSetT)];
- __builtin_memcpy(__sbuffer, &__expr1_set, sizeof(_MatchingSetT));
- __buffer.append_range(__sbuffer);
- __write_uleb(__buffer, __instr_start - __again_pos);
- __machine_.erase(__machine_.begin() + __instr_start, __machine_.begin() + __instr_start + __instr_size);
- __machine_.insert(__machine_.begin() + __instr_start, __buffer.begin(), __buffer.end());
- __fix_jumps(__instr_start, __buffer.size() - __instr_size);
- }
- [[clang::musttail]] return __optimize();
- }
- }
- break;
- }
-
- case __branch_alternative:
-
- // End state
- case __end_state:
- return;
- }
- }
- }
-
void __push_any_matcher() { push_back(__state::__match_any); }
void __push_any_except_newline_matcher() { push_back(__state::__match_any_except_newline); }
void __push_end_state() { push_back(__state::__end_state); }
@@ -1228,7 +1051,6 @@ class __interpreter {
size_t size() const { return __machine_.size(); }
- // [[clang::preserve_none]]
pair<bool, const _CharT*>
__execute(__global_execution_state<_CharT, _Traits>& __gexec_state,
const _CharT* __first,
>From 8a084d8a072853fbd83563be58fc0ecf16313085 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 20 Aug 2026 23:06:20 +0200
Subject: [PATCH 19/21] fix lookahead
---
libcxx/include/__regex/basic_parser.h | 1 -
libcxx/include/__regex/ecma_parser.h | 1 -
libcxx/include/__regex/interpreter.h | 264 ++++++++++++++------------
libcxx/include/__regex/regex_error.h | 2 +
4 files changed, 141 insertions(+), 127 deletions(-)
diff --git a/libcxx/include/__regex/basic_parser.h b/libcxx/include/__regex/basic_parser.h
index e9948015dcd84..9b8caeb688f4a 100644
--- a/libcxx/include/__regex/basic_parser.h
+++ b/libcxx/include/__regex/basic_parser.h
@@ -229,7 +229,6 @@ class __parser {
void __parse_basic() {
__parse_basic_expr();
__machine_.__push_end_state();
- __machine_.__optimize();
}
void __parse_grep() {
diff --git a/libcxx/include/__regex/ecma_parser.h b/libcxx/include/__regex/ecma_parser.h
index 06bb235caeeb9..6499349410a0e 100644
--- a/libcxx/include/__regex/ecma_parser.h
+++ b/libcxx/include/__regex/ecma_parser.h
@@ -294,7 +294,6 @@ class __parser {
if (__first_ != __last_)
std::__throw_regex_error<regex_constants::__re_err_parse>();
__machine_.__push_end_state();
- __machine_.__optimize();
}
__interpreter<_CharT, _Traits> __extract_interpreter() { return std::move(__machine_); }
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index b9c38fd6b9468..cb9977b03c11b 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -13,6 +13,7 @@
#include <__algorithm/equal.h>
#include <__algorithm/min.h>
#include <__algorithm/reverse.h>
+#include <__algorithm/reverse_copy.h>
#include <__algorithm/transform.h>
#include <__config>
#include <__iterator/back_insert_iterator.h>
@@ -372,42 +373,43 @@ struct __local_execution_state {
return {__found, false, __current_pos};
}
- /*
-pair<bool, size_t> __exec_lookahead(
- const _CharT* const __first,
- const _CharT* const __last,
- const __global_state& __gstate,
- const __interpreter_info<_CharT>* const __code,
- size_t __current_pos,
- bool __is_positive) {
- auto __jump_offset = __read_uleb(__code, __current_pos);
- auto __submatch_count = __read_uleb(__code, __current_pos);
- auto __submatch_base = __read_uleb(__code, __current_pos);
- auto __loop_count = __read_uleb(__code, __current_pos);
-
- auto __initial_loop_values = std::make_unique_for_overwrite<__loop_value<_CharT>[]>(__loop_count);
-
- for (size_t __i = 0; __i != __loop_count; ++__i)
- __initial_loop_values[__i] = __read_uleb(__code, __current_pos);
-
- __global_state __gexec_state{{}, __gstate.__machine_, __submatch_count, __gstate.__flags_};
- __gexec_state.__flags_ &= ~regex_constants::__full_match;
- auto& __s = __gexec_state.__states_.emplace_back();
- if (__loop_count > 0)
- __s.__sub_matches_ = std::make_unique<pair<const _CharT*, const _CharT*>[]>(__submatch_count);
- __s.__current_ = __current_;
- __s.__loop_values_ = std::move(__initial_loop_values);
- __s.__current_pos_ = __current_pos;
- if (__gexec_state.__execute(__first, __last) != __is_positive)
- return {false, __current_pos};
- if (__is_positive) {
- auto& __matched_state = __gexec_state.__states_.back();
- std::copy_n(__matched_state.__sub_matches_.get(), __submatch_count, __get_submatch(__submatch_base));
+ pair<bool, size_t> __exec_lookahead(
+ const _CharT* const __first,
+ const _CharT* const __last,
+ const _CharT* __current,
+ const __global_state& __gstate,
+ const __interpreter_info<_CharT>* const __code,
+ size_t __current_pos,
+ bool __is_positive) {
+ auto __jump_offset = __read_uleb(__code, __current_pos);
+ auto __submatch_count = __read_uleb(__code, __current_pos);
+ auto __submatch_base = __read_uleb(__code, __current_pos);
+ auto __loop_count = __read_uleb(__code, __current_pos);
+
+ vector<__loop_value<_CharT>> __initial_loop_values;
+
+ for (size_t __i = 0; __i != __loop_count; ++__i)
+ __initial_loop_values.push_back(__read_uleb(__code, __current_pos));
+
+ __global_state __gexec_state{
+ {__loop_count, __gstate.__states_.__get_submatch_count()},
+ __gstate.__machine_,
+ __submatch_count,
+ __gstate.__flags_};
+ __gexec_state.__flags_ &= ~regex_constants::__full_match;
+ vector<sub_match<const _CharT*>> __sub_matches;
+ if (__gexec_state.__execute(__first, __current, __last, __sub_matches, __current_pos, __initial_loop_values)
+ .first != __is_positive)
+ return {false, __current_pos};
+ if (__is_positive) {
+ size_t __index = 0;
+ for (auto __iter = __sub_matches.begin(); __iter != __sub_matches.end(); ++__iter) {
+ __get_submatch(__submatch_base + __index++) = *__iter;
+ }
+ }
+ __current_pos += __jump_offset;
+ return {true, __current_pos};
}
- __current_pos += __jump_offset;
- return {true, __current_pos};
-}
- */
size_t __exec_branch_n_to_m_matcher(
__global_state& __gstate,
@@ -616,13 +618,13 @@ pair<bool, size_t> __exec_lookahead(
case __negative_lookahead:
case __positive_lookahead: {
- // if (auto __result =
- // __exec_lookahead(__first, __last, __gstate, __code, __current_pos, (__st == __positive_lookahead));
- // __result.first)
- // __current_pos = __result.second;
- // else
- // return {false, __counter};
- } // break;
+ if (auto __result = __exec_lookahead(
+ __first, __last, __current, __gstate, __code, __current_pos, (__st == __positive_lookahead));
+ __result.first)
+ __current_pos = __result.second;
+ else
+ return {false, __counter};
+ } break;
default:
std::__libcpp_unreachable();
@@ -634,8 +636,8 @@ pair<bool, size_t> __exec_lookahead(
template <class _CharT, class _Traits>
class __local_execution_state_stack {
char* __data_begin_ = nullptr;
- size_t __base_offset_;
- size_t __object_size_;
+ const size_t __base_offset_;
+ const size_t __object_size_;
size_t __size_ = 0;
size_t __capacity_ = 0;
@@ -652,6 +654,8 @@ class __local_execution_state_stack {
__local_execution_state_stack& operator=(const __local_execution_state_stack&) = delete;
~__local_execution_state_stack() { __builtin_free(__data_begin_); }
+ size_t __get_submatch_count() const { return __base_offset_ / sizeof(pair<const _CharT*, const _CharT*>); }
+
bool empty() const { return __size_ == 0; }
value_type& back() {
@@ -736,6 +740,96 @@ struct __global_execution_state {
return false;
}
}
+
+ pair<bool, const _CharT*>
+ __execute(const _CharT* __first,
+ const _CharT* __current,
+ const _CharT* __last,
+ vector<sub_match<const _CharT*>>& __sub_matches,
+ size_t __exec_pos,
+ const vector<__loop_value<_CharT>>& __initial_loop_values) {
+ using __local_state = __local_execution_state<_CharT, _Traits>;
+
+ auto __copy_to_submatches =
+ [&](pair<const _CharT*, const _CharT*>* __from, size_t __count, vector<sub_match<const _CharT*>>& __to) {
+ __to.clear();
+ std::transform(
+ std::make_reverse_iterator(__from + __count),
+ std::make_reverse_iterator(__from),
+ std::back_inserter(__to),
+ [&](pair<const _CharT*, const _CharT*> __v) {
+ sub_match<const _CharT*> __ret;
+ __ret.first = __v.first ? __v.first : __last;
+ __ret.second = __v.first ? __v.second : __last;
+ __ret.matched = __v.first;
+ return __ret;
+ });
+ };
+
+ const auto __sizeof_submatches = sizeof(pair<const _CharT*, const _CharT*>) * __submatch_count_;
+ const auto __sizeof_loop_values = sizeof(__loop_value<_CharT>) * __initial_loop_values.size();
+ const auto __state_size = __sizeof_submatches + sizeof(__local_state) + __sizeof_loop_values;
+
+ auto* __base_state_start = static_cast<char*>(__builtin_alloca(2 * __state_size));
+ auto* __base_state_submatches = reinterpret_cast<pair<const _CharT*, const _CharT*>*>(__base_state_start);
+ auto* __base_state = reinterpret_cast<__local_state*>(__base_state_start + __sizeof_submatches);
+ auto* __tmp_state_start = __base_state_start + __state_size;
+ auto* __tmp_state = reinterpret_cast<__local_state*>(__tmp_state_start + __sizeof_submatches);
+
+ std::uninitialized_fill_n(
+ __base_state_submatches, __submatch_count_, pair<const _CharT*, const _CharT*>{nullptr, nullptr});
+ std::__construct_at(__base_state, __current, __exec_pos);
+ std::uninitialized_copy(
+ __initial_loop_values.begin(),
+ __initial_loop_values.end(),
+ reinterpret_cast<__loop_value<_CharT>*>(__base_state_start + __sizeof_submatches + sizeof(__local_state)));
+
+ auto [__base_state_matched, __gcounter] = __base_state->__execute(__first, __last, *this);
+
+ size_t __length = __last - __first + 1;
+ if (__machine_.__find_longest_) {
+ if (!__base_state_matched)
+ __base_state->__current_ = __current;
+ bool __found_match = __base_state_matched;
+ while (!__states_.empty()) {
+ if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ std::__throw_regex_error<regex_constants::error_complexity>();
+ __states_.pop(__tmp_state);
+ auto [__success, __counter] = __tmp_state->__execute(__first, __last, *this);
+ __gcounter += __counter;
+ if (__success) {
+ if (!__found_match || __base_state->__current_ < __tmp_state->__current_)
+ __builtin_memcpy(__base_state_start, __tmp_state_start, __state_size);
+ if (__base_state->__current_ == __last) {
+ __copy_to_submatches(__base_state_submatches, __submatch_count_, __sub_matches);
+ return {true, __base_state->__current_};
+ }
+ __found_match = true;
+ }
+ }
+ if (!__found_match)
+ return {false, {}};
+ __copy_to_submatches(__base_state_submatches, __submatch_count_, __sub_matches);
+ return {true, __base_state->__current_};
+ } else {
+ if (__base_state_matched) {
+ __copy_to_submatches(__base_state_submatches, __submatch_count_, __sub_matches);
+ return {true, __base_state->__current_};
+ }
+ while (!__states_.empty()) {
+ if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
+ std::__throw_regex_error<regex_constants::error_complexity>();
+ __states_.pop(__base_state);
+ if (auto [__success, __counter] = __base_state->__execute(__first, __last, *this); __success) {
+ __copy_to_submatches(__base_state_submatches, __submatch_count_, __sub_matches);
+ return {true, __base_state->__current_};
+ } else {
+ __gcounter += __counter;
+ }
+ }
+ return {false, {}};
+ }
+ }
};
template <class _CharT, class _Traits>
@@ -1056,87 +1150,7 @@ class __interpreter {
const _CharT* __first,
const _CharT* __last,
vector<sub_match<const _CharT*>>& __sub_matches) const {
- using __local_state = __local_execution_state<_CharT, _Traits>;
-
- auto __copy_to_submatches =
- [&](pair<const _CharT*, const _CharT*>* __from, size_t __count, vector<sub_match<const _CharT*>>& __to) {
- __to.clear();
- std::transform(
- std::make_reverse_iterator(__from + __count),
- std::make_reverse_iterator(__from),
- std::back_inserter(__to),
- [&](pair<const _CharT*, const _CharT*> __v) {
- sub_match<const _CharT*> __ret;
- __ret.first = __v.first ? __v.first : __last;
- __ret.second = __v.first ? __v.second : __last;
- __ret.matched = __v.first;
- return __ret;
- });
- };
-
- const auto __sizeof_submatches = sizeof(pair<const _CharT*, const _CharT*>) * __gexec_state.__submatch_count_;
- const auto __sizeof_loop_values = sizeof(__loop_value<_CharT>) * __initial_loop_values_.size();
- const auto __state_size = __sizeof_submatches + sizeof(__local_state) + __sizeof_loop_values;
-
- auto* __base_state_start = static_cast<char*>(__builtin_alloca(2 * __state_size));
- auto* __base_state_submatches = reinterpret_cast<pair<const _CharT*, const _CharT*>*>(__base_state_start);
- auto* __base_state = reinterpret_cast<__local_state*>(__base_state_start + __sizeof_submatches);
- auto* __tmp_state_start = __base_state_start + __state_size;
- auto* __tmp_state = reinterpret_cast<__local_state*>(__tmp_state_start + __sizeof_submatches);
-
- std::uninitialized_fill_n(
- __base_state_submatches, __gexec_state.__submatch_count_, pair<const _CharT*, const _CharT*>{nullptr, nullptr});
- std::__construct_at(__base_state, __first, 0);
- std::uninitialized_copy(
- __initial_loop_values_.begin(),
- __initial_loop_values_.end(),
- reinterpret_cast<__loop_value<_CharT>*>(__base_state_start + __sizeof_submatches + sizeof(__local_state)));
-
- auto [__base_state_matched, __gcounter] = __base_state->__execute(__first, __last, __gexec_state);
-
- size_t __length = __last - __first + 1;
- if (__gexec_state.__machine_.__find_longest_) {
- if (!__base_state_matched)
- __base_state->__current_ = __first;
- bool __found_match = __base_state_matched;
- while (!__gexec_state.__states_.empty()) {
- if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
- std::__throw_regex_error<regex_constants::error_complexity>();
- __gexec_state.__states_.pop(__tmp_state);
- auto [__success, __counter] = __tmp_state->__execute(__first, __last, __gexec_state);
- __gcounter += __counter;
- if (__success) {
- if (!__found_match || __base_state->__current_ < __tmp_state->__current_)
- __builtin_memcpy(__base_state_start, __tmp_state_start, __state_size);
- if (__base_state->__current_ == __last) {
- __copy_to_submatches(__base_state_submatches, __gexec_state.__submatch_count_, __sub_matches);
- return {true, __base_state->__current_};
- }
- __found_match = true;
- }
- }
- if (!__found_match)
- return {false, {}};
- __copy_to_submatches(__base_state_submatches, __gexec_state.__submatch_count_, __sub_matches);
- return {true, __base_state->__current_};
- } else {
- if (__base_state_matched) {
- __copy_to_submatches(__base_state_submatches, __gexec_state.__submatch_count_, __sub_matches);
- return {true, __base_state->__current_};
- }
- while (!__gexec_state.__states_.empty()) {
- if (__gcounter / _LIBCPP_REGEX_COMPLEXITY_FACTOR >= __length)
- std::__throw_regex_error<regex_constants::error_complexity>();
- __gexec_state.__states_.pop(__base_state);
- if (auto [__success, __counter] = __base_state->__execute(__first, __last, __gexec_state); __success) {
- __copy_to_submatches(__base_state_submatches, __gexec_state.__submatch_count_, __sub_matches);
- return {true, __base_state->__current_};
- } else {
- __gcounter += __counter;
- }
- }
- return {false, {}};
- }
+ return __gexec_state.__execute(__first, __first, __last, __sub_matches, 0, __initial_loop_values_);
}
pair<bool, const _CharT*> __execute_match(
diff --git a/libcxx/include/__regex/regex_error.h b/libcxx/include/__regex/regex_error.h
index 4bf29d74c7282..35f8cb2ed6147 100644
--- a/libcxx/include/__regex/regex_error.h
+++ b/libcxx/include/__regex/regex_error.h
@@ -155,6 +155,7 @@ enum error_type {
} // namespace regex_constants
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
class _LIBCPP_EXPORTED_FROM_ABI regex_error : public runtime_error {
regex_constants::error_type __code_;
@@ -164,6 +165,7 @@ class _LIBCPP_EXPORTED_FROM_ABI regex_error : public runtime_error {
~regex_error() _NOEXCEPT override;
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI regex_constants::error_type code() const { return __code_; }
};
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
template <regex_constants::error_type _Ev>
[[__noreturn__]] inline _LIBCPP_HIDE_FROM_ABI void __throw_regex_error() {
>From 51e0fd702c7075cdce4c7d4d9656c300d40ec49e Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 21 Aug 2026 15:53:08 +0200
Subject: [PATCH 20/21] Fixes
---
libcxx/include/__regex/basic_parser.h | 6 +-
libcxx/include/__regex/ecma_parser.h | 6 +-
libcxx/include/__regex/extended_parser.h | 4 +-
libcxx/include/__regex/interpreter.h | 79 ++++++++++++------------
libcxx/include/__regex/parser_common.h | 4 +-
libcxx/include/regex | 10 +--
6 files changed, 52 insertions(+), 57 deletions(-)
diff --git a/libcxx/include/__regex/basic_parser.h b/libcxx/include/__regex/basic_parser.h
index 9b8caeb688f4a..27f4093e785dc 100644
--- a/libcxx/include/__regex/basic_parser.h
+++ b/libcxx/include/__regex/basic_parser.h
@@ -9,17 +9,15 @@
#ifndef _LIBCPP___REGEX_BASIC_PARSER_H
#define _LIBCPP___REGEX_BASIC_PARSER_H
-#include <__algorithm/search.h>
#include <__config>
#include <__iterator/next.h>
#include <__regex/interpreter.h>
#include <__regex/parser_common.h>
#include <__regex/regex_error.h>
-#include <__utility/exchange.h>
_LIBCPP_BEGIN_NAMESPACE_STD
-namespace __regex::__basic::inline __preserve_none {
+namespace __regex::__basic {
template <class _CharT, class _Traits, class _ForwardIterator>
class __parser {
@@ -260,7 +258,7 @@ class __parser {
__interpreter<_CharT, _Traits> __extract_interpreter() { return std::move(__machine_); }
size_t mark_count() const { return __marked_count_; }
};
-} // namespace __regex::__basic::inline __preserve_none
+} // namespace __regex::__basic
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__regex/ecma_parser.h b/libcxx/include/__regex/ecma_parser.h
index 6499349410a0e..4e0599ad1add8 100644
--- a/libcxx/include/__regex/ecma_parser.h
+++ b/libcxx/include/__regex/ecma_parser.h
@@ -11,7 +11,9 @@
#include <__config>
#include <__regex/interpreter.h>
+#include <__regex/parser_common.h>
#include <__regex/regex_error.h>
+#include <__utility/exchange.h>
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -211,7 +213,7 @@ class __parser {
}
case '[':
- return __parse_bracket_expression(__machine_, __first_, __last_, __flags_);
+ return __regex::__parse_bracket_expression(__machine_, __first_, __last_, __flags_);
case '(': {
++__first_;
@@ -263,7 +265,7 @@ class __parser {
if (!__parse_atom())
return false;
- __parse_dupl_symbol(__machine_, __first_, __last_, __expr_start, true);
+ __regex::__parse_dupl_symbol(__machine_, __first_, __last_, __expr_start, true);
return true;
}
diff --git a/libcxx/include/__regex/extended_parser.h b/libcxx/include/__regex/extended_parser.h
index 76e2fa411a422..0176883fd4bc8 100644
--- a/libcxx/include/__regex/extended_parser.h
+++ b/libcxx/include/__regex/extended_parser.h
@@ -9,13 +9,11 @@
#ifndef _LIBCPP___REGEX_EXTENDED_PARSER_H
#define _LIBCPP___REGEX_EXTENDED_PARSER_H
-#include <__algorithm/search.h>
#include <__config>
#include <__iterator/next.h>
#include <__regex/interpreter.h>
#include <__regex/parser_common.h>
#include <__regex/regex_error.h>
-#include <__utility/exchange.h>
#include <string>
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -81,7 +79,7 @@ class __parser {
default:
if (regex_constants::__get_grammar(__flags_) == regex_constants::awk) {
__first_ = __next;
- __machine_.__push_char_matcher(__parse_awk_escape<_CharT>(__first_, __last_));
+ __machine_.__push_char_matcher(__regex::__parse_awk_escape<_CharT>(__first_, __last_));
return true;
}
auto __val = __machine_.__get_traits().value(*__next, 10);
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index cb9977b03c11b..8a9afab40cd6a 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -9,21 +9,18 @@
#ifndef _LIBCPP___REGEX_INTERPRETER_H
#define _LIBCPP___REGEX_INTERPRETER_H
-#include <__algorithm/copy_if.h>
#include <__algorithm/equal.h>
-#include <__algorithm/min.h>
-#include <__algorithm/reverse.h>
-#include <__algorithm/reverse_copy.h>
#include <__algorithm/transform.h>
#include <__config>
#include <__iterator/back_insert_iterator.h>
#include <__locale_dir/ctype_base.h>
+#include <__memory/uninitialized_algorithms.h>
#include <__regex/regex_error.h>
+#include <__type_traits/make_signed.h>
#include <__utility/pair.h>
#include <__utility/scope_guard.h>
-#include <__utility/to_underlying.h>
+#include <__utility/unreachable.h>
#include <__vector/vector.h>
-#include <stack>
#include <string_view>
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -73,8 +70,8 @@ struct __state {
};
namespace __regex {
-using _MatchingSetT = unsigned _BitInt(256);
-using _MatchingSetWithEndT = unsigned _BitInt(257);
+using _MatchingSetT _LIBCPP_NODEBUG = unsigned _BitInt(256);
+using _MatchingSetWithEndT _LIBCPP_NODEBUG = unsigned _BitInt(257);
enum class __state : uint8_t {
// Anchors
@@ -156,7 +153,7 @@ template <class _CharT>
size_t __read_uleb(const __interpreter_info<_CharT>* __machine, size_t& __current_pos) {
auto __val = __machine[__current_pos++].__int_;
if (__val & 0x80) {
- auto __res = __read_uleb_impl(__machine, __current_pos);
+ auto __res = __regex::__read_uleb_impl(__machine, __current_pos);
__current_pos = __res.second;
return __res.first;
}
@@ -210,7 +207,7 @@ struct __global_execution_state;
template <class _CharT, class _Traits>
struct __local_execution_state {
- using __global_state = __global_execution_state<_CharT, _Traits>;
+ using __global_state _LIBCPP_NODEBUG = __global_execution_state<_CharT, _Traits>;
pair<const _CharT*, const _CharT*>& __get_submatch(size_t __n) {
return *reinterpret_cast<pair<const _CharT*, const _CharT*>*>(
@@ -259,19 +256,19 @@ struct __local_execution_state {
for (size_t __i = 0; __i != __buffer_size; ++__i)
__buffer[__i] = __code[__current_pos++].__char_;
typename _Traits::char_class_type __mask;
- __builtin_memcpy(&__mask, __buffer, sizeof(typename _Traits::char_class_type));
+ __builtin_memcpy(std::addressof(__mask), __buffer, sizeof(typename _Traits::char_class_type));
for (size_t __i = 0; __i != __buffer_size; ++__i)
__buffer[__i] = __code[__current_pos++].__char_;
typename _Traits::char_class_type __neg_mask;
- __builtin_memcpy(&__neg_mask, __buffer, sizeof(typename _Traits::char_class_type));
+ __builtin_memcpy(std::addressof(__neg_mask), __buffer, sizeof(typename _Traits::char_class_type));
- auto __chars = __read_uleb(__code, __current_pos);
- auto __digraphs = __read_uleb(__code, __current_pos) * 2;
- auto __ranges = __read_uleb(__code, __current_pos) * 4;
- auto __neg_chars = __read_uleb(__code, __current_pos);
- auto __equiv_count = __read_uleb(__code, __current_pos);
- auto __equiv_size = __read_uleb(__code, __current_pos);
+ auto __chars = __regex::__read_uleb(__code, __current_pos);
+ auto __digraphs = __regex::__read_uleb(__code, __current_pos) * 2;
+ auto __ranges = __regex::__read_uleb(__code, __current_pos) * 4;
+ auto __neg_chars = __regex::__read_uleb(__code, __current_pos);
+ auto __equiv_count = __regex::__read_uleb(__code, __current_pos);
+ auto __equiv_size = __regex::__read_uleb(__code, __current_pos);
bool __found = false;
@@ -355,7 +352,7 @@ struct __local_execution_state {
auto __after_pos = __current_pos + __equiv_size;
auto __transformed = __gstate.__machine_.__traits_.transform_primary(__current, __current + 1);
for (size_t __i = 0; __i != __equiv_count; ++__i) {
- auto __size = __read_uleb(__code, __current_pos);
+ auto __size = __regex::__read_uleb(__code, __current_pos);
basic_string<_CharT> __str;
std::transform(__code + __current_pos,
__code + __current_pos + __size,
@@ -381,15 +378,15 @@ struct __local_execution_state {
const __interpreter_info<_CharT>* const __code,
size_t __current_pos,
bool __is_positive) {
- auto __jump_offset = __read_uleb(__code, __current_pos);
- auto __submatch_count = __read_uleb(__code, __current_pos);
- auto __submatch_base = __read_uleb(__code, __current_pos);
- auto __loop_count = __read_uleb(__code, __current_pos);
+ auto __jump_offset = __regex::__read_uleb(__code, __current_pos);
+ auto __submatch_count = __regex::__read_uleb(__code, __current_pos);
+ auto __submatch_base = __regex::__read_uleb(__code, __current_pos);
+ auto __loop_count = __regex::__read_uleb(__code, __current_pos);
vector<__loop_value<_CharT>> __initial_loop_values;
for (size_t __i = 0; __i != __loop_count; ++__i)
- __initial_loop_values.push_back(__read_uleb(__code, __current_pos));
+ __initial_loop_values.push_back(__regex::__read_uleb(__code, __current_pos));
__global_state __gexec_state{
{__loop_count, __gstate.__states_.__get_submatch_count()},
@@ -417,9 +414,9 @@ struct __local_execution_state {
const _CharT* const __current,
size_t __current_pos,
bool __is_greedy) {
- auto __loop_index = __read_uleb(__code, __current_pos);
+ auto __loop_index = __regex::__read_uleb(__code, __current_pos);
auto __again_pos_base = __current_pos;
- auto __again_pos = __again_pos_base - __read_uleb(__code, __current_pos);
+ auto __again_pos = __again_pos_base - __regex::__read_uleb(__code, __current_pos);
if (__loop_values_[__loop_index + 1].__int_ > 0) {
--__loop_values_[__loop_index + 1].__int_;
__current_pos = __again_pos;
@@ -508,14 +505,14 @@ struct __local_execution_state {
} break;
case __branch_alternative: {
- auto __offset = __read_uleb(__code, __current_pos);
+ auto __offset = __regex::__read_uleb(__code, __current_pos);
__gstate.__states_.push(this);
__gstate.__states_.back().__current_ = __current;
__gstate.__states_.back().__current_pos_ = __current_pos + __offset;
} break;
case __relative_jump: {
- __current_pos += __read_uleb(__code, __current_pos);
+ __current_pos += __regex::__read_uleb(__code, __current_pos);
} break;
case __conditional_jump_forward:
@@ -523,7 +520,7 @@ struct __local_execution_state {
_MatchingSetT __set;
__builtin_memcpy(&__set, __code + __current_pos, sizeof(_MatchingSetT));
__current_pos += sizeof(_MatchingSetT);
- auto __jump_offset = std::__to_signed_like(__read_uleb(__code, __current_pos));
+ auto __jump_offset = std::__to_signed_like(__regex::__read_uleb(__code, __current_pos));
if (__st == __conditional_jump_backward)
__jump_offset *= -1;
if (__current == __last)
@@ -539,7 +536,7 @@ struct __local_execution_state {
} break;
case __match_backref: {
- auto& __match = __get_submatch(__read_uleb(__code, __current_pos) - 1);
+ auto& __match = __get_submatch(__regex::__read_uleb(__code, __current_pos) - 1);
if (__match.first == nullptr)
return {false, __counter};
@@ -551,7 +548,7 @@ struct __local_execution_state {
} break;
case __match_icase_backref: {
- auto& __match = __get_submatch(__read_uleb(__code, __current_pos) - 1);
+ auto& __match = __get_submatch(__regex::__read_uleb(__code, __current_pos) - 1);
if (__match.first == nullptr)
return {false, __counter};
@@ -597,12 +594,12 @@ struct __local_execution_state {
} break;
case __marked_subexpression_begin: {
- auto __match = __read_uleb(__code, __current_pos);
+ auto __match = __regex::__read_uleb(__code, __current_pos);
__get_submatch(__match).first = __current;
} break;
case __marked_subexpression_end: {
- auto __match = __read_uleb(__code, __current_pos);
+ auto __match = __regex::__read_uleb(__code, __current_pos);
__get_submatch(__match).second = __current;
} break;
@@ -896,19 +893,19 @@ class __interpreter {
case __marked_subexpression_begin:
case __marked_subexpression_end: {
- __read_uleb(__m, __pos);
+ __regex::__read_uleb(__m, __pos);
return __get_possibly_matching_characters(__m, __pos);
}
case __relative_jump: {
- __pos += __read_uleb(__m, __pos);
+ __pos += __regex::__read_uleb(__m, __pos);
return __get_possibly_matching_characters(__m, __pos);
}
case __branch_n_to_m_matcher:
case __branch_nongreedy_n_to_m_matcher: {
- auto __loop_index = __read_uleb(__m, __pos);
- __read_uleb(__m, __pos);
+ auto __loop_index = __regex::__read_uleb(__m, __pos);
+ __regex::__read_uleb(__m, __pos);
if (__initial_loop_values_[__loop_index + 1].__int_ == 0)
return ~_MatchingSetWithEndT();
return __get_possibly_matching_characters(__m, __pos);
@@ -935,7 +932,7 @@ class __interpreter {
_MatchingSetT __set;
__builtin_memcpy(&__set, __m + __pos, sizeof(_MatchingSetT));
__pos += sizeof(_MatchingSetT);
- auto __jump_offset = std::__to_signed_like(__read_uleb(__m, __pos));
+ auto __jump_offset = std::__to_signed_like(__regex::__read_uleb(__m, __pos));
if (__state == __conditional_jump_backward)
__jump_offset *= -1;
return __set | __get_possibly_matching_characters(__m, __pos + __jump_offset);
@@ -1025,7 +1022,7 @@ class __interpreter {
(__expr1_set & __get_possibly_matching_characters(__machine_.data(), __expr2_start)) == _MatchingSetT()) {
__buffer.push_back(__state::__conditional_jump_forward);
__interpreter_info<_CharT> __sbuffer[sizeof(_MatchingSetT)];
- __builtin_memcpy(__sbuffer, &__expr1_set, sizeof(_MatchingSetT));
+ __builtin_memcpy(__sbuffer, std::addressof(__expr1_set), sizeof(_MatchingSetT));
__buffer.append_range(__sbuffer);
__write_uleb(__buffer, __expr2_start - __expr1_start);
insert(__expr1_start, __buffer);
@@ -1094,9 +1091,9 @@ class __interpreter {
push_back(__negate ? __state::__match_no_character_list : __state::__match_character_list);
_CharT __buffer[std::max(sizeof(typename _Traits::char_class_type) / sizeof(_CharT), size_t(1))];
- __builtin_memcpy(__buffer, &__expr.__mask_, sizeof(__buffer));
+ __builtin_memcpy(__buffer, std::addressof(__expr.__mask_), sizeof(__buffer));
append_range(__buffer);
- __builtin_memcpy(__buffer, &__expr.__neg_mask_, sizeof(__buffer));
+ __builtin_memcpy(__buffer, std::addressof(__expr.__neg_mask_), sizeof(__buffer));
append_range(__buffer);
basic_string<_CharT> __equivalences_buffer;
diff --git a/libcxx/include/__regex/parser_common.h b/libcxx/include/__regex/parser_common.h
index f7ea5418b0cc0..b47da1eb24987 100644
--- a/libcxx/include/__regex/parser_common.h
+++ b/libcxx/include/__regex/parser_common.h
@@ -350,12 +350,12 @@ bool __parse_expression_term(
return false;
if (*__first == '[' && *__next == '.') {
__first = ++__next;
- __parse_collating_symbol(__machine, __end_range, __first, __last);
+ __regex::__parse_collating_symbol(__machine, __end_range, __first, __last);
} else if (auto __grammar = regex_constants::__get_grammar(__flags);
__grammar == regex_constants::awk && *__first == '\\') {
if (++__first == __last)
return false;
- __start_range = __parse_awk_escape<_CharT>(__first, __last);
+ __start_range = __regex::__parse_awk_escape<_CharT>(__first, __last);
} else if (__grammar == regex_constants::ECMAScript && *__first == '\\') {
if (++__first == __last)
return false;
diff --git a/libcxx/include/regex b/libcxx/include/regex
index c5bad522a16f0..5b2fb412317d8 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -1242,7 +1242,7 @@ class __owns_one_state : public __has_one_state<_CharT> {
public:
_LIBCPP_HIDE_FROM_ABI explicit __owns_one_state(__node<_CharT>* __s) : base(__s) {}
- ~__owns_one_state() override;
+ _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~__owns_one_state() override;
};
template <class _CharT>
@@ -1273,9 +1273,9 @@ void __empty_state<_CharT>::__exec(__state& __s) const {
template <class _CharT>
class __regex_search_state : public __empty_state<_CharT> {
public:
- explicit __regex_search_state(__node<_CharT>* __s) : __empty_state<_CharT>(__s) {}
+ _LIBCPP_HIDE_FROM_ABI explicit __regex_search_state(__node<_CharT>* __s) : __empty_state<_CharT>(__s) {}
- virtual __regex::__search_result<_CharT> __exec_regex_search(
+ _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual __regex::__search_result<_CharT> __exec_regex_search(
const _CharT* __first, const _CharT* __last, regex_constants::match_flag_type, size_t __marked_count) = 0;
};
@@ -1298,7 +1298,7 @@ public:
__state.__current_ = __res.second;
}
- __regex::__search_result<_CharT> __exec_regex_search(
+ _LIBCPP_HIDE_FROM_ABI __regex::__search_result<_CharT> __exec_regex_search(
const _CharT* __first,
const _CharT* __last,
regex_constants::match_flag_type __flags,
@@ -2591,7 +2591,7 @@ bool basic_regex<_CharT, _Traits>::__search(
return false;
}
vector<sub_match<const _CharT*>> __sub_matches(std::move(__res.__sub_matches_));
- std::__destroy_at(&__res.__sub_matches_);
+ std::__destroy_at(std::addressof(__res.__sub_matches_));
__m.__matches_[0].first = __res.__match_first_;
__m.__matches_[0].second = __res.__match_last_;
__m.__matches_[0].matched = true;
>From 2808b5a183828664ef1545dfb8c1eb4f52051b27 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 21 Aug 2026 16:47:16 +0200
Subject: [PATCH 21/21] More fixes
---
libcxx/include/__regex/basic_parser.h | 15 +++++++++++++++
libcxx/include/__regex/ecma_parser.h | 15 +++++++++++++++
libcxx/include/__regex/extended_parser.h | 11 +++++++++++
libcxx/include/__regex/interpreter.h | 12 ++++++++++++
libcxx/include/__regex/parser_common.h | 15 +++++++++++++++
libcxx/include/__regex/regex_error.h | 4 ++++
libcxx/include/module.modulemap.in | 10 +++++++++-
7 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__regex/basic_parser.h b/libcxx/include/__regex/basic_parser.h
index 27f4093e785dc..cb777b7894334 100644
--- a/libcxx/include/__regex/basic_parser.h
+++ b/libcxx/include/__regex/basic_parser.h
@@ -9,11 +9,24 @@
#ifndef _LIBCPP___REGEX_BASIC_PARSER_H
#define _LIBCPP___REGEX_BASIC_PARSER_H
+#include <__algorithm/find.h>
#include <__config>
+#include <__cstddef/size_t.h>
#include <__iterator/next.h>
#include <__regex/interpreter.h>
#include <__regex/parser_common.h>
#include <__regex/regex_error.h>
+#include <__utility/move.h>
+#include <__utility/swap.h>
+#include <cstdint>
+#include <limits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -262,4 +275,6 @@ class __parser {
_LIBCPP_END_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___REGEX_BASIC_PARSER_H
diff --git a/libcxx/include/__regex/ecma_parser.h b/libcxx/include/__regex/ecma_parser.h
index 4e0599ad1add8..8b55c66a25083 100644
--- a/libcxx/include/__regex/ecma_parser.h
+++ b/libcxx/include/__regex/ecma_parser.h
@@ -10,10 +10,23 @@
#define _LIBCPP___REGEX_ECMA_PARSER_H
#include <__config>
+#include <__cstddef/size_t.h>
+#include <__iterator/next.h>
+#include <__locale_dir/ctype_base.h>
#include <__regex/interpreter.h>
#include <__regex/parser_common.h>
#include <__regex/regex_error.h>
#include <__utility/exchange.h>
+#include <__utility/move.h>
+#include <cstdint>
+#include <limits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -305,4 +318,6 @@ class __parser {
_LIBCPP_END_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___REGEX_ECMA_PARSER_H
diff --git a/libcxx/include/__regex/extended_parser.h b/libcxx/include/__regex/extended_parser.h
index 0176883fd4bc8..9a48fa4662e5c 100644
--- a/libcxx/include/__regex/extended_parser.h
+++ b/libcxx/include/__regex/extended_parser.h
@@ -9,13 +9,22 @@
#ifndef _LIBCPP___REGEX_EXTENDED_PARSER_H
#define _LIBCPP___REGEX_EXTENDED_PARSER_H
+#include <__algorithm/find.h>
#include <__config>
#include <__iterator/next.h>
#include <__regex/interpreter.h>
#include <__regex/parser_common.h>
#include <__regex/regex_error.h>
+#include <cstdint>
#include <string>
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
_LIBCPP_BEGIN_NAMESPACE_STD
namespace __regex::__extended {
@@ -213,4 +222,6 @@ class __parser {
_LIBCPP_END_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___REGEX_EXTENDED_PARSER_H
diff --git a/libcxx/include/__regex/interpreter.h b/libcxx/include/__regex/interpreter.h
index 8a9afab40cd6a..73a5f1a4d7d7b 100644
--- a/libcxx/include/__regex/interpreter.h
+++ b/libcxx/include/__regex/interpreter.h
@@ -10,19 +10,29 @@
#define _LIBCPP___REGEX_INTERPRETER_H
#include <__algorithm/equal.h>
+#include <__algorithm/max.h>
#include <__algorithm/transform.h>
#include <__config>
#include <__iterator/back_insert_iterator.h>
#include <__locale_dir/ctype_base.h>
+#include <__memory/construct_at.h>
#include <__memory/uninitialized_algorithms.h>
#include <__regex/regex_error.h>
#include <__type_traits/make_signed.h>
+#include <__utility/move.h>
#include <__utility/pair.h>
#include <__utility/scope_guard.h>
#include <__utility/unreachable.h>
#include <__vector/vector.h>
#include <string_view>
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _CharT>
@@ -1206,4 +1216,6 @@ class __interpreter {
_LIBCPP_END_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___REGEX_INTERPRETER_H
diff --git a/libcxx/include/__regex/parser_common.h b/libcxx/include/__regex/parser_common.h
index b47da1eb24987..6635b64724480 100644
--- a/libcxx/include/__regex/parser_common.h
+++ b/libcxx/include/__regex/parser_common.h
@@ -11,8 +11,21 @@
#include <__algorithm/search.h>
#include <__config>
+#include <__cstddef/size_t.h>
+#include <__iterator/next.h>
+#include <__locale_dir/ctype_base.h>
#include <__regex/interpreter.h>
#include <__regex/regex_error.h>
+#include <__utility/move.h>
+#include <limits>
+#include <string>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -550,4 +563,6 @@ bool __parse_dupl_symbol(
_LIBCPP_END_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___REGEX_BASIC_PARSER_H
diff --git a/libcxx/include/__regex/regex_error.h b/libcxx/include/__regex/regex_error.h
index 35f8cb2ed6147..2dcdfc3780bac 100644
--- a/libcxx/include/__regex/regex_error.h
+++ b/libcxx/include/__regex/regex_error.h
@@ -12,6 +12,10 @@
#include <__config>
#include <stdexcept>
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
_LIBCPP_BEGIN_NAMESPACE_STD
#define _LIBCPP_REGEX_COMPLEXITY_FACTOR 4096
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 4512cc71153ca..ad20f1d2b7ecf 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1701,7 +1701,7 @@ module std {
module noexcept_move_assign_container { header "__memory/noexcept_move_assign_container.h" }
module out_ptr { header "__memory/out_ptr.h" }
module pointer_traits { header "__memory/pointer_traits.h" }
- module pstl { header "__memory/pstl.h" }
+ module pstl { header "__memory/pstl.h" }
module ranges_construct_at { header "__memory/ranges_construct_at.h" }
module ranges_destroy { header "__memory/ranges_destroy.h" }
module ranges_uninitialized_algorithms {
@@ -2055,6 +2055,14 @@ module std {
module regex {
header "regex"
+
+ module basic_parser { header "__regex/basic_parser.h" }
+ module ecma_parser { header "__regex/ecma_parser.h" }
+ module extended_parser { header "__regex/extended_parser.h" }
+ module interpreter { header "__regex/interpreter.h" }
+ module parser_common { header "__regex/parser_common.h" }
+ module regex_error { header "__regex/regex_error.h" }
+
export *
export std.iterator.reverse_iterator
}
More information about the libcxx-commits
mailing list