Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions libcxx/include/regex
Original file line number Diff line number Diff line change
Expand Up @@ -1668,7 +1668,7 @@ void __end_marked_subexpression<_CharT>::__exec(__state& __s) const {

// __back_ref

template <class _CharT>
template <class _CharT, bool _UnmatchedAlwaysSucceed>
class __back_ref : public __owns_one_state<_CharT> {
typedef __owns_one_state<_CharT> base;

Expand All @@ -1682,8 +1682,8 @@ public:
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
};

template <class _CharT>
void __back_ref<_CharT>::__exec(__state& __s) const {
template <class _CharT, bool _UnmatchedAlwaysSucceed>
void __back_ref<_CharT, _UnmatchedAlwaysSucceed>::__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];
Expand All @@ -1697,6 +1697,9 @@ void __back_ref<_CharT>::__exec(__state& __s) const {
__s.__do_ = __state::__reject;
__s.__node_ = nullptr;
}
} else if constexpr (_UnmatchedAlwaysSucceed) {
__s.__do_ = __state::__accept_but_not_consume;
__s.__node_ = this->first();;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repeated semicolon. (clang-format didn't suggest to remove it, but it's better to do so.)

Suggested change
__s.__node_ = this->first();;
__s.__node_ = this->first();

} else {
__s.__do_ = __state::__reject;
__s.__node_ = nullptr;
Expand All @@ -1705,7 +1708,7 @@ void __back_ref<_CharT>::__exec(__state& __s) const {

// __back_ref_icase

template <class _CharT, class _Traits>
template <class _CharT, class _Traits, bool _UnmatchedAlwaysSucceed>
class __back_ref_icase : public __owns_one_state<_CharT> {
typedef __owns_one_state<_CharT> base;

Expand All @@ -1721,8 +1724,8 @@ public:
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __exec(__state&) const;
};

template <class _CharT, class _Traits>
void __back_ref_icase<_CharT, _Traits>::__exec(__state& __s) const {
template <class _CharT, class _Traits, bool _UnmatchedAlwaysSucceed>
void __back_ref_icase<_CharT, _Traits, _UnmatchedAlwaysSucceed>::__exec(__state& __s) const {
sub_match<const _CharT*>& __sm = __s.__sub_matches_[__mexp_ - 1];
if (__sm.matched) {
ptrdiff_t __len = __sm.second - __sm.first;
Expand All @@ -1739,6 +1742,11 @@ void __back_ref_icase<_CharT, _Traits>::__exec(__state& __s) const {
__s.__node_ = nullptr;
}
} else {
if constexpr (_UnmatchedAlwaysSucceed) {
__s.__do_ = __state::__accept_but_not_consume;
__s.__node_ = this->first();
return;
}
__not_equal:
__s.__do_ = __state::__reject;
__s.__node_ = nullptr;
Expand All @@ -1747,7 +1755,7 @@ void __back_ref_icase<_CharT, _Traits>::__exec(__state& __s) const {

// __back_ref_collate

template <class _CharT, class _Traits>
template <class _CharT, class _Traits, bool _UnmatchedAlwaysSucceed>
class __back_ref_collate : public __owns_one_state<_CharT> {
typedef __owns_one_state<_CharT> base;

Expand All @@ -1763,8 +1771,8 @@ public:
_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 {
template <class _CharT, class _Traits, bool _UnmatchedAlwaysSucceed>
void __back_ref_collate<_CharT, _Traits, _UnmatchedAlwaysSucceed>::__exec(__state& __s) const {
sub_match<const _CharT*>& __sm = __s.__sub_matches_[__mexp_ - 1];
if (__sm.matched) {
ptrdiff_t __len = __sm.second - __sm.first;
Expand All @@ -1781,6 +1789,11 @@ void __back_ref_collate<_CharT, _Traits>::__exec(__state& __s) const {
__s.__node_ = nullptr;
}
} else {
if constexpr (_UnmatchedAlwaysSucceed) {
__s.__do_ = __state::__accept_but_not_consume;
__s.__node_ = this->first();
return;
}
__not_equal:
__s.__do_ = __state::__reject;
__s.__node_ = nullptr;
Expand Down Expand Up @@ -2565,6 +2578,7 @@ private:
bool __greedy = true);
__bracket_expression<_CharT, _Traits>* __start_matching_list(bool __negate);
void __push_char(value_type __c);
template <bool _UnmatchedAlwaysSucceed = false>
void __push_back_ref(int __i);
void __push_alternation(__owns_one_state<_CharT>* __sa, __owns_one_state<_CharT>* __sb);
void __push_begin_marked_subexpression();
Expand Down Expand Up @@ -3807,7 +3821,7 @@ basic_regex<_CharT, _Traits>::__parse_decimal_escape(_ForwardIterator __first, _
}
if (__v == 0 || __v > mark_count())
std::__throw_regex_error<regex_constants::error_backref>();
__push_back_ref(__v);
__push_back_ref<true>(__v);
}
}
return __first;
Expand Down Expand Up @@ -4149,13 +4163,14 @@ void basic_regex<_CharT, _Traits>::__push_word_boundary(bool __invert) {
}

template <class _CharT, class _Traits>
template <bool _UnmatchedAlwaysSucceed>
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());
__end_->first() = new __back_ref_icase<_CharT, _Traits, _UnmatchedAlwaysSucceed>(__traits_, __i, __end_->first());
else if (flags() & collate)
__end_->first() = new __back_ref_collate<_CharT, _Traits>(__traits_, __i, __end_->first());
__end_->first() = new __back_ref_collate<_CharT, _Traits, _UnmatchedAlwaysSucceed>(__traits_, __i, __end_->first());
else
__end_->first() = new __back_ref<_CharT>(__i, __end_->first());
__end_->first() = new __back_ref<_CharT, _UnmatchedAlwaysSucceed>(__i, __end_->first());
__end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
}

Expand Down
30 changes: 30 additions & 0 deletions libcxx/test/std/re/re.alg/re.alg.search/ecma.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,21 @@ int main(int, char**)
assert(m.position(0) == 0);
assert(m.str(0) == s);
}
{
std::cmatch m;
const char s[] = "a";
assert(std::regex_search(s, m, std::regex{"(a()|)\\2a"}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test also runs in C++03 mode. Ditto below.

Suggested change
assert(std::regex_search(s, m, std::regex{"(a()|)\\2a"}));
assert(std::regex_search(s, m, std::regex("(a()|)\\2a")));

assert(m.size() == 3);
assert(!m.prefix().matched);
assert(m.prefix().first == s);
assert(m.prefix().second == m[0].first);
assert(!m.suffix().matched);
assert(m.suffix().first == m[0].second);
assert(m.suffix().second == s + std::char_traits<char>::length(s));
assert(m.length(0) >= 0 && static_cast<std::size_t>(m.length(0)) == std::char_traits<char>::length(s));
assert(m.position(0) == 0);
assert(m.str(0) == s);
}

#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
Expand Down Expand Up @@ -1503,6 +1518,21 @@ int main(int, char**)
assert(m.position(0) == 0);
assert(m.str(0) == s);
}
{
std::wcmatch m;
const wchar_t s[] = L"a";
assert(std::regex_search(s, m, std::wregex{L"(a()|)\\2a"}));
assert(m.size() == 3);
assert(!m.prefix().matched);
assert(m.prefix().first == s);
assert(m.prefix().second == m[0].first);
assert(!m.suffix().matched);
assert(m.suffix().first == m[0].second);
assert(m.suffix().second == s + std::char_traits<wchar_t>::length(s));
assert(m.length(0) >= 0 && static_cast<std::size_t>(m.length(0)) == std::char_traits<wchar_t>::length(s));
assert(m.position(0) == 0);
assert(m.str(0) == s);
}
#endif // TEST_HAS_NO_WIDE_CHARACTERS

return 0;
Expand Down
Loading