LibRegex: Add RegexStringView wrapper to support utf8 and utf32 views

This commit is contained in:
Emanuel Sprung 2020-06-09 00:15:09 +02:00 committed by Andreas Kling
parent 12dd40a2a5
commit 4a630d4b63
Notes: sideshowbarker 2024-07-19 01:15:10 +09:00
11 changed files with 596 additions and 304 deletions

View file

@ -79,7 +79,7 @@ int regcomp(regex_t* reg, const char* pattern, int cflags)
preg->cflags = cflags;
String pattern_str(pattern);
preg->re = make<Regex<PosixExtended>>(pattern_str, PosixOptions {} | (PosixFlags)cflags);
preg->re = make<Regex<PosixExtended>>(pattern_str, PosixOptions {} | (PosixFlags)cflags | PosixFlags::SkipTrimEmptyMatches);
auto parser_result = preg->re->parser_result;
if (parser_result.error != regex::Error::NoError) {
@ -109,9 +109,9 @@ int regexec(const regex_t* reg, const char* string, size_t nmatch, regmatch_t pm
RegexResult result;
if (eflags & REG_SEARCH)
result = preg->re->search({ string }, PosixOptions {} | (PosixFlags)eflags);
result = preg->re->search(string, PosixOptions {} | (PosixFlags)eflags);
else
result = preg->re->match({ string }, PosixOptions {} | (PosixFlags)eflags);
result = preg->re->match(string, PosixOptions {} | (PosixFlags)eflags);
if (result.success) {
auto size = result.matches.size();

View file

@ -47,8 +47,10 @@ class OpCode_SaveLeftNamedCaptureGroup;
class OpCode_SaveNamedLeftCaptureGroup;
class OpCode_SaveRightNamedCaptureGroup;
class OpCode_Compare;
class RegexStringView;
}
using regex::Error;
using regex::Lexer;
using regex::PosixExtendedParser;
using regex::RegexStringView;

View file

@ -346,7 +346,7 @@ ALWAYS_INLINE ExecutionResult OpCode_Compare::execute(const MatchInput& input, M
return ExecutionResult::Failed_ExecuteLowPrioForks;
auto character_class = (CharClass)m_bytecode->at(offset++);
auto& ch = input.view[state.string_position];
auto ch = input.view[state.string_position];
compare_character_class(input, state, character_class, ch, inverse, inverse_matched);
@ -375,10 +375,9 @@ ALWAYS_INLINE ExecutionResult OpCode_Compare::execute(const MatchInput& input, M
return ExecutionResult::Continue;
}
ALWAYS_INLINE void OpCode_Compare::compare_char(const MatchInput& input, MatchState& state, char& ch, bool inverse, bool& inverse_matched) const
ALWAYS_INLINE void OpCode_Compare::compare_char(const MatchInput& input, MatchState& state, u32 ch1, bool inverse, bool& inverse_matched)
{
auto ch1 = ch;
auto ch2 = input.view[state.string_position];
u32 ch2 = input.view[state.string_position];
if (input.regex_options & AllFlags::Insensitive) {
ch1 = tolower(ch1);
@ -393,26 +392,30 @@ ALWAYS_INLINE void OpCode_Compare::compare_char(const MatchInput& input, MatchSt
}
}
ALWAYS_INLINE bool OpCode_Compare::compare_string(const MatchInput& input, MatchState& state, const char* str, size_t length) const
ALWAYS_INLINE bool OpCode_Compare::compare_string(const MatchInput& input, MatchState& state, const char* str, size_t length)
{
auto str_view1 = StringView(str, length);
auto str_view2 = StringView(&input.view[state.string_position], length);
String str1, str2;
if (input.regex_options & AllFlags::Insensitive) {
str1 = str_view1.to_string().to_lowercase();
str2 = str_view2.to_string().to_lowercase();
str_view1 = str1.view();
str_view2 = str2.view();
if (input.view.is_u8_view()) {
auto str_view1 = StringView(str, length);
auto str_view2 = StringView(&input.view.u8view()[state.string_position], length);
String str1, str2;
if (input.regex_options & AllFlags::Insensitive) {
str1 = str_view1.to_string().to_lowercase();
str2 = str_view2.to_string().to_lowercase();
str_view1 = str1.view();
str_view2 = str2.view();
}
if (str_view1 == str_view2) {
state.string_position += length;
return true;
}
}
if (str_view1 == str_view2) {
state.string_position += length;
return true;
} else
return false;
return false;
}
ALWAYS_INLINE void OpCode_Compare::compare_character_class(const MatchInput& input, MatchState& state, CharClass character_class, char ch, bool inverse, bool& inverse_matched) const
ALWAYS_INLINE void OpCode_Compare::compare_character_class(const MatchInput& input, MatchState& state, CharClass character_class, char ch, bool inverse, bool& inverse_matched)
{
switch (character_class) {
case CharClass::Alnum:
@ -510,7 +513,7 @@ ALWAYS_INLINE void OpCode_Compare::compare_character_class(const MatchInput& inp
}
}
ALWAYS_INLINE void OpCode_Compare::compare_character_range(const MatchInput& input, MatchState& state, char from, char to, char ch, bool inverse, bool& inverse_matched) const
ALWAYS_INLINE void OpCode_Compare::compare_character_range(const MatchInput& input, MatchState& state, char from, char to, char ch, bool inverse, bool& inverse_matched)
{
if (input.regex_options & AllFlags::Insensitive) {
from = tolower(from);
@ -536,9 +539,7 @@ const Vector<String> OpCode_Compare::variable_arguments_to_string(Optional<Match
Vector<String> result;
size_t offset { state().instruction_position + 3 };
StringView view;
if (input.has_value())
view = input.value().view;
RegexStringView view = ((input.has_value()) ? input.value().view : nullptr);
for (size_t i = 0; i < arguments_count(); ++i) {
auto compare_type = (CharacterCompareType)m_bytecode->at(offset++);
@ -548,23 +549,23 @@ const Vector<String> OpCode_Compare::variable_arguments_to_string(Optional<Match
char ch = m_bytecode->at(offset++);
result.empend(String::format("value='%c'", ch));
if (!view.is_null())
result.empend(String::format("compare against: '%s'", String { view.substring_view(state().string_position, state().string_position + 1 > view.length() ? 0 : 1) }.characters()));
result.empend(String::format("compare against: '%s'", view.substring_view(state().string_position, state().string_position + 1 > view.length() ? 0 : 1).to_string().characters()));
} else if (compare_type == CharacterCompareType::String) {
char* str = reinterpret_cast<char*>(m_bytecode->at(offset++));
auto& length = m_bytecode->at(offset++);
result.empend(String::format("value=\"%s\"", String { str, length }.characters()));
if (!view.is_null())
result.empend(String::format("compare against: \"%s\"", String { input.value().view.substring_view(state().string_position, state().string_position + length > view.length() ? 0 : length) }.characters()));
result.empend(String::format("compare against: \"%s\"", input.value().view.substring_view(state().string_position, state().string_position + length > view.length() ? 0 : length).to_string().characters()));
} else if (compare_type == CharacterCompareType::CharClass) {
auto character_class = (CharClass)m_bytecode->at(offset++);
result.empend(String::format("ch_class=%lu [%s]", (size_t)character_class, character_class_name(character_class)));
if (!view.is_null())
result.empend(String::format("compare against: '%s'", String { input.value().view.substring_view(state().string_position, state().string_position + 1 > view.length() ? 0 : 1) }.characters()));
result.empend(String::format("compare against: '%s'", input.value().view.substring_view(state().string_position, state().string_position + 1 > view.length() ? 0 : 1).to_string().characters()));
} else if (compare_type == CharacterCompareType::CharRange) {
auto value = (CharRange)m_bytecode->at(offset++);
result.empend(String::format("ch_range='%c'-'%c'", value.from, value.to));
if (!view.is_null())
result.empend(String::format("compare against: '%s'", String { input.value().view.substring_view(state().string_position, state().string_position + 1 > view.length() ? 0 : 1) }.characters()));
result.empend(String::format("compare against: '%s'", input.value().view.substring_view(state().string_position, state().string_position + 1 > view.length() ? 0 : 1).to_string().characters()));
}
}
return result;

View file

@ -407,7 +407,6 @@ protected:
Optional<MatchState*> m_state;
};
class OpCode_Exit final : public OpCode {
public:
OpCode_Exit(ByteCode& bytecode)
@ -567,10 +566,10 @@ public:
const Vector<String> variable_arguments_to_string(Optional<MatchInput> input = {}) const;
private:
ALWAYS_INLINE void compare_char(const MatchInput& input, MatchState& state, char& ch, bool inverse, bool& inverse_matched) const;
ALWAYS_INLINE bool compare_string(const MatchInput& input, MatchState& state, const char* str, size_t length) const;
ALWAYS_INLINE void compare_character_class(const MatchInput& input, MatchState& state, CharClass character_class, char ch, bool inverse, bool& inverse_matched) const;
ALWAYS_INLINE void compare_character_range(const MatchInput& input, MatchState& state, char from, char to, char ch, bool inverse, bool& inverse_matched) const;
ALWAYS_INLINE static void compare_char(const MatchInput& input, MatchState& state, u32 ch1, bool inverse, bool& inverse_matched);
ALWAYS_INLINE static bool compare_string(const MatchInput& input, MatchState& state, const char* str, size_t length);
ALWAYS_INLINE static void compare_character_class(const MatchInput& input, MatchState& state, CharClass character_class, char ch, bool inverse, bool& inverse_matched);
ALWAYS_INLINE static void compare_character_range(const MatchInput& input, MatchState& state, char from, char to, char ch, bool inverse, bool& inverse_matched);
};
template<typename T>

View file

@ -31,11 +31,196 @@
#include "AK/FlyString.h"
#include "AK/HashMap.h"
#include "AK/String.h"
#include "AK/StringBuilder.h"
#include "AK/StringView.h"
#include "AK/Utf32View.h"
#include "AK/Vector.h"
namespace regex {
class RegexStringView {
public:
RegexStringView(const char* chars)
: m_u8view(chars)
{
}
RegexStringView(const String& string)
: m_u8view(string)
{
}
RegexStringView(const StringView view)
: m_u8view(view)
{
}
RegexStringView(const Utf32View view)
: m_u32view(view)
{
}
bool is_u8_view() const { return m_u8view.has_value(); }
bool is_u32_view() const { return m_u32view.has_value(); }
const StringView& u8view() const
{
ASSERT(m_u8view.has_value());
return m_u8view.value();
};
const Utf32View& u32view() const
{
ASSERT(m_u32view.has_value());
return m_u32view.value();
};
bool is_empty() const
{
if (is_u8_view())
return m_u8view.value().is_empty();
else
return m_u32view.value().is_empty();
}
bool is_null() const
{
if (is_u8_view())
return m_u8view.value().is_null();
else
return m_u32view.value().code_points() == nullptr;
}
size_t length() const
{
if (is_u8_view())
return m_u8view.value().length();
else
return m_u32view.value().length();
}
Vector<RegexStringView> lines() const
{
if (is_u8_view()) {
auto views = u8view().lines(false);
Vector<RegexStringView> new_views;
for (auto& view : views)
new_views.append(move(view));
return new_views;
}
// FIXME: line splitting for Utf32View needed
Vector<RegexStringView> views;
views.append(m_u32view.value());
return views;
}
RegexStringView substring_view(size_t offset, size_t length) const
{
if (is_u8_view()) {
return u8view().substring_view(offset, length);
}
return u32view().substring_view(offset, length);
}
String to_string() const
{
if (is_u8_view()) {
return u8view().to_string();
}
StringBuilder builder;
builder.append(u32view());
return builder.to_string();
}
u32 operator[](size_t index) const
{
if (is_u8_view()) {
return u8view()[index];
}
return u32view().code_points()[index];
}
bool operator==(const char* cstring) const
{
if (is_u8_view())
return u8view() == cstring;
return to_string() == cstring;
}
bool operator!=(const char* cstring) const
{
return !(*this == cstring);
}
bool operator==(const String& string) const
{
if (is_u8_view())
return u8view() == string;
return to_string() == string;
}
bool operator==(const StringView& other) const
{
if (is_u8_view())
return u8view() == other;
return false;
}
bool operator!=(const StringView& other) const
{
return !(*this == other);
}
bool operator==(const Utf32View& other) const
{
if (is_u32_view()) {
StringBuilder builder;
builder.append(other);
return to_string() == builder.to_string();
}
return false;
}
bool operator!=(const Utf32View& other) const
{
return !(*this == other);
}
const char* characters_without_null_termination() const
{
if(is_u8_view())
return u8view().characters_without_null_termination();
return to_string().characters(); // FIXME: it contains the null termination, does that actually matter?
}
bool starts_with(const StringView& str) const
{
if(is_u32_view())
return false;
return u8view().starts_with(str);
}
bool starts_with(const Utf32View& str) const
{
if(is_u8_view())
return false;
StringBuilder builder;
builder.append(str);
return to_string().starts_with(builder.to_string());
}
private:
Optional<StringView> m_u8view;
Optional<Utf32View> m_u32view;
};
class Match final {
private:
Optional<FlyString> string;
@ -44,7 +229,7 @@ public:
Match() = default;
~Match() = default;
Match(const StringView view_, const size_t line_, const size_t column_, const size_t global_offset_)
Match(const RegexStringView view_, const size_t line_, const size_t column_, const size_t global_offset_)
: view(view_)
, line(line_)
, column(column_)
@ -63,7 +248,7 @@ public:
{
}
StringView view { nullptr };
RegexStringView view { nullptr };
size_t line { 0 };
size_t column { 0 };
size_t global_offset { 0 };
@ -74,14 +259,14 @@ public:
};
struct MatchInput {
StringView view { nullptr };
RegexStringView view { nullptr };
AllOptions regex_options {};
size_t match_index { 0 };
size_t line { 0 };
size_t column { 0 };
size_t global_offset { 0 }; // For multiline matching, knowning the offset from start could be important
size_t global_offset { 0 }; // For multiline matching, knowing the offset from start could be important
};
struct MatchState {
@ -98,3 +283,5 @@ struct MatchOutput {
};
}
using regex::RegexStringView;

View file

@ -66,10 +66,22 @@ String Regex<Parser>::error_string(Optional<String> message) const
}
template<typename Parser>
RegexResult Matcher<Parser>::match(const StringView& view, Optional<typename ParserTraits<Parser>::OptionsType> regex_options) const
RegexResult Matcher<Parser>::match(const RegexStringView& view, Optional<typename ParserTraits<Parser>::OptionsType> regex_options) const
{
AllOptions options = m_regex_options | regex_options.value_or({}).value();
if (options.has_flag_set(AllFlags::Multiline))
return match(view.lines(), regex_options); // FIXME: how do we know, which line ending a line has (1char or 2char)? This is needed to get the correct match offsets from start of string...
Vector<RegexStringView> views;
views.append(view);
return match(views, regex_options);
}
template<typename Parser>
RegexResult Matcher<Parser>::match(const Vector<RegexStringView> views, Optional<typename ParserTraits<Parser>::OptionsType> regex_options) const
{
size_t match_count { 0 };
Vector<StringView> views { view };
MatchInput input;
MatchState state;
@ -78,9 +90,6 @@ RegexResult Matcher<Parser>::match(const StringView& view, Optional<typename Par
input.regex_options = m_regex_options | regex_options.value_or({}).value();
output.operations = 0;
if (input.regex_options & AllFlags::Multiline)
views = view.lines(false); // FIXME: how do we know, which line ending a line has (1char or 2char)? This is needed to get the correct match offsets from start of string...
if (c_match_preallocation_count) {
output.matches.ensure_capacity(c_match_preallocation_count);
output.capture_group_matches.ensure_capacity(c_match_preallocation_count);
@ -192,7 +201,16 @@ RegexResult Matcher<Parser>::match(const StringView& view, Optional<typename Par
if (match_count) {
auto capture_groups_count = min(output.capture_group_matches.size(), output.matches.size());
for (size_t i = 0; i < capture_groups_count; ++i) {
output_copy.capture_group_matches.append(output.capture_group_matches.at(i));
if(input.regex_options & AllFlags::SkipTrimEmptyMatches) {
output_copy.capture_group_matches.append(output.capture_group_matches.at(i));
} else {
Vector<Match> capture_group_matches;
for (size_t j = 0; j < output.capture_group_matches.at(i).size(); ++j) {
if (!output.capture_group_matches.at(i).at(j).view.is_null())
capture_group_matches.append(output.capture_group_matches.at(i).at(j));
}
output_copy.capture_group_matches.append(capture_group_matches);
}
}
auto named_capture_groups_count = min(output.named_capture_group_matches.size(), output.matches.size());
@ -216,6 +234,8 @@ RegexResult Matcher<Parser>::match(const StringView& view, Optional<typename Par
move(output_copy.capture_group_matches),
move(output_copy.named_capture_group_matches),
output.operations,
m_pattern.parser_result.capture_groups_count,
m_pattern.parser_result.named_capture_groups_count,
};
}
@ -306,7 +326,7 @@ ALWAYS_INLINE Optional<bool> Matcher<Parser>::execute_low_prio_forks(const Match
original_state.string_position = 0;
return false;
};
}
template class Matcher<PosixExtendedParser>;
template class Regex<PosixExtendedParser>;

View file

@ -35,6 +35,7 @@
#include <AK/HashMap.h>
#include <AK/NonnullOwnPtrVector.h>
#include <AK/Types.h>
#include <AK/Utf32View.h>
#include <AK/Vector.h>
#include <stdio.h>
@ -50,7 +51,9 @@ struct RegexResult final {
Vector<Match> matches;
Vector<Vector<Match>> capture_group_matches;
Vector<HashMap<String, Match>> named_capture_group_matches;
size_t operations { 0 };
size_t n_operations { 0 };
size_t n_capture_groups { 0 };
size_t n_named_capture_groups { 0 };
};
template<class Parser>
@ -67,7 +70,8 @@ public:
}
~Matcher() = default;
RegexResult match(const StringView&, Optional<typename ParserTraits<Parser>::OptionsType> = {}) const;
RegexResult match(const RegexStringView&, Optional<typename ParserTraits<Parser>::OptionsType> = {}) const;
RegexResult match(const Vector<RegexStringView>, Optional<typename ParserTraits<Parser>::OptionsType> = {}) const;
private:
Optional<bool> execute(const MatchInput& input, MatchState& state, MatchOutput& output, size_t recursion_level) const;
@ -84,20 +88,27 @@ public:
regex::Parser::Result parser_result;
OwnPtr<Matcher<Parser>> matcher { nullptr };
Regex(StringView pattern, typename ParserTraits<Parser>::OptionsType regex_options = {});
explicit Regex(StringView pattern, typename ParserTraits<Parser>::OptionsType regex_options = {});
~Regex() = default;
void print_bytecode(FILE* f = stdout) const;
String error_string(Optional<String> message = {}) const;
RegexResult match(StringView view, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
RegexResult match(const RegexStringView view, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
if (!matcher || parser_result.error != Error::NoError)
return {};
return matcher->match(view, regex_options);
}
RegexResult search(StringView view, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
RegexResult match(const Vector<RegexStringView> views, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
if (!matcher || parser_result.error != Error::NoError)
return {};
return matcher->match(views, regex_options);
}
RegexResult search(const RegexStringView view, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
if (!matcher || parser_result.error != Error::NoError)
return {};
@ -112,72 +123,123 @@ public:
return matcher->match(view, options);
}
bool match(StringView view, RegexResult& m, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
RegexResult search(const Vector<RegexStringView> views, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
if (!matcher || parser_result.error != Error::NoError)
return {};
m = matcher->match(view, regex_options);
AllOptions options = (AllOptions)regex_options.value_or({});
if ((options & AllFlags::MatchNotBeginOfLine) && (options & AllFlags::MatchNotEndOfLine)) {
options.reset_flag(AllFlags::MatchNotEndOfLine);
options.reset_flag(AllFlags::MatchNotBeginOfLine);
}
options |= AllFlags::Global;
return matcher->match(views, options);
}
bool match(const RegexStringView view, RegexResult& m, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
m = match(view, regex_options);
return m.success;
}
bool search(StringView view, RegexResult& m, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
bool match(const Vector<RegexStringView> views, RegexResult& m, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
m = match(views, regex_options);
return m.success;
}
bool search(const RegexStringView view, RegexResult& m, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
m = search(view, regex_options);
return m.success;
}
bool has_match(const StringView view, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
bool search(const Vector<RegexStringView> views, RegexResult& m, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
m = search(views, regex_options);
return m.success;
}
bool has_match(const RegexStringView view, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
if (!matcher || parser_result.error != Error::NoError)
return false;
RegexResult result = matcher->match(view, AllOptions { regex_options.value_or({}) } | AllFlags::SkipSubExprResults);
return result.success;
}
bool has_match(const Vector<RegexStringView> views, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {}) const
{
if (!matcher || parser_result.error != Error::NoError)
return false;
RegexResult result = matcher->match(views, AllOptions { regex_options.value_or({}) } | AllFlags::SkipSubExprResults);
return result.success;
}
};
// free standing functions for match, search and has_match
template<class Parser>
RegexResult match(const StringView view, Regex<Parser>& pattern, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
RegexResult match(const RegexStringView view, Regex<Parser>& pattern, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
if (!pattern.matcher || pattern.parser_result.error != Error::NoError)
return {};
return pattern.matcher->match(view, regex_options);
return pattern.match(view, regex_options);
}
template<class Parser>
bool match(const StringView view, Regex<Parser>& pattern, RegexResult& res, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
RegexResult match(const Vector<RegexStringView> view, Regex<Parser>& pattern, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
if (!pattern.matcher || pattern.parser_result.error != Error::NoError)
return {};
res = pattern.matcher->match(view, regex_options);
return res.success;
return pattern.match(view, regex_options);
}
template<class Parser>
RegexResult search(const StringView view, Regex<Parser>& pattern, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
bool match(const RegexStringView view, Regex<Parser>& pattern, RegexResult& res, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
if (!pattern.matcher || pattern.parser_result.error != Error::NoError)
return {};
return pattern.matcher->search(view, regex_options);
return pattern.match(view, regex_options);
}
template<class Parser>
bool search(const StringView view, Regex<Parser>& pattern, RegexResult& res, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
bool match(const Vector<RegexStringView> view, Regex<Parser>& pattern, RegexResult& res, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
if (!pattern.matcher || pattern.parser_result.error != Error::NoError)
return {};
res = pattern.matcher->search(view, regex_options);
return res.success;
return pattern.match(view, regex_options);
}
template<class Parser>
bool has_match(const StringView view, Regex<Parser>& pattern, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
RegexResult search(const RegexStringView view, Regex<Parser>& pattern, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
if (pattern.matcher == nullptr)
return {};
RegexResult result = pattern.matcher->match(view, AllOptions { regex_options.value_or({}) } | AllFlags::SkipSubExprResults);
return result.success;
return pattern.search(view, regex_options);
}
template<class Parser>
RegexResult search(const Vector<RegexStringView> views, Regex<Parser>& pattern, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
return pattern.search(views, regex_options);
}
template<class Parser>
bool search(const RegexStringView view, Regex<Parser>& pattern, RegexResult& res, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
return pattern.search(view, regex_options);
}
template<class Parser>
bool search(const Vector<RegexStringView> views, Regex<Parser>& pattern, RegexResult& res, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
return pattern.search(views, regex_options);
}
template<class Parser>
bool has_match(const RegexStringView view, Regex<Parser>& pattern, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
return pattern.has_match(view, regex_options);
}
template<class Parser>
bool has_match(const Vector<RegexStringView> views, Regex<Parser>& pattern, Optional<typename ParserTraits<Parser>::OptionsType> regex_options = {})
{
return pattern.has_match(views, regex_options);
}
}
using regex::has_match;

View file

@ -66,6 +66,7 @@ enum class PosixFlags : FlagsUnderlyingType {
MatchNotBeginOfLine = (FlagsUnderlyingType)AllFlags::MatchNotBeginOfLine,
MatchNotEndOfLine = (FlagsUnderlyingType)AllFlags::MatchNotEndOfLine,
SkipSubExprResults = (FlagsUnderlyingType)AllFlags::SkipSubExprResults,
SkipTrimEmptyMatches = (FlagsUnderlyingType)AllFlags::SkipTrimEmptyMatches,
Multiline = (FlagsUnderlyingType)AllFlags::Multiline,
StringCopyMatches = (FlagsUnderlyingType)AllFlags::StringCopyMatches,
};

View file

@ -42,6 +42,12 @@
# include <regex>
# endif
# if not(defined(REGEX_BENCHMARK_OUR) && defined(REGEX_BENCHMARK_OUR))
BENCHMARK_CASE(dummy_benchmark)
{
}
# endif
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(catch_all_benchmark)
{
@ -51,10 +57,10 @@ BENCHMARK_CASE(catch_all_benchmark)
EXPECT(re.match("Hello World", m));
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(catch_all_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(catch_all_benchmark_reference_stdcpp)
{
std::regex re("^.*$");
std::cmatch m;
@ -62,9 +68,9 @@ BENCHMARK_CASE(catch_all_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("Hello World", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_start_benchmark)
{
Regex<PosixExtended> re("^hello friends");
@ -75,10 +81,10 @@ BENCHMARK_CASE(simple_start_benchmark)
EXPECT_EQ(re.match("Well, hello friends", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_start_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_start_benchmark_reference_stdcpp)
{
std::regex re("^hello friends");
std::cmatch m;
@ -88,9 +94,9 @@ BENCHMARK_CASE(simple_start_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("Well, hello friends", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_end_benchmark)
{
Regex<PosixExtended> re(".*hello\\.\\.\\. there$");
@ -102,10 +108,10 @@ BENCHMARK_CASE(simple_end_benchmark)
EXPECT_EQ(re.match("hello.. there", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_end_benchmark_reference_stdcpp_regex_search)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_end_benchmark_reference_stdcpp)
{
std::regex re(".*hello\\.\\.\\. there$");
std::cmatch m;
@ -116,9 +122,9 @@ BENCHMARK_CASE(simple_end_benchmark_reference_stdcpp_regex_search)
EXPECT_EQ(std::regex_search("hello.. there", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_period_benchmark)
{
Regex<PosixExtended> re("hello.");
@ -130,10 +136,10 @@ BENCHMARK_CASE(simple_period_benchmark)
EXPECT_EQ(re.match("hello?", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_period_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_period_benchmark_reference_stdcpp)
{
std::regex re("hello.");
std::cmatch m;
@ -144,9 +150,9 @@ BENCHMARK_CASE(simple_period_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("hello?", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_period_end_benchmark)
{
Regex<PosixExtended> re("hello.$");
@ -158,10 +164,10 @@ BENCHMARK_CASE(simple_period_end_benchmark)
EXPECT_EQ(re.search("hello?", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_period_end_benchmark_reference_stdcpp_regex_search)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_period_end_benchmark_reference_stdcpp)
{
std::regex re("hello.$");
std::cmatch m;
@ -172,9 +178,9 @@ BENCHMARK_CASE(simple_period_end_benchmark_reference_stdcpp_regex_search)
EXPECT_EQ(std::regex_search("hello?", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_escaped_benchmark)
{
Regex<PosixExtended> re("hello\\.");
@ -184,10 +190,10 @@ BENCHMARK_CASE(simple_escaped_benchmark)
EXPECT_EQ(re.match("hello.", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_escaped_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_escaped_benchmark_reference_stdcpp)
{
std::regex re("hello\\.");
std::cmatch m;
@ -196,9 +202,9 @@ BENCHMARK_CASE(simple_escaped_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("hello.", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_period2_end_benchmark)
{
Regex<PosixExtended> re(".*hi... there$");
@ -211,10 +217,10 @@ BENCHMARK_CASE(simple_period2_end_benchmark)
EXPECT_EQ(re.search("I said fyhihi there", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_period2_end_benchmark_reference_stdcpp_regex_search)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_period2_end_benchmark_reference_stdcpp)
{
std::regex re(".*hi... there$");
std::cmatch m;
@ -226,9 +232,9 @@ BENCHMARK_CASE(simple_period2_end_benchmark_reference_stdcpp_regex_search)
EXPECT_EQ(std::regex_search("I said fyhihi there", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_plus_benchmark)
{
Regex<PosixExtended> re("a+");
@ -240,10 +246,10 @@ BENCHMARK_CASE(simple_plus_benchmark)
EXPECT_EQ(re.search("aaaaaaaaaaa", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_plus_benchmark_reference_stdcpp_regex_search)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_plus_benchmark_reference_stdcpp)
{
std::regex re("a+");
std::cmatch m;
@ -254,9 +260,9 @@ BENCHMARK_CASE(simple_plus_benchmark_reference_stdcpp_regex_search)
EXPECT_EQ(std::regex_search("aaaaaaaaaaa", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_questionmark_benchmark)
{
Regex<PosixExtended> re("da?d");
@ -271,10 +277,10 @@ BENCHMARK_CASE(simple_questionmark_benchmark)
EXPECT_EQ(re.search("adadaa", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_questionmark_benchmark_reference_stdcpp_regex_search)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_questionmark_benchmark_reference_stdcpp)
{
std::regex re("da?d");
std::cmatch m;
@ -288,9 +294,9 @@ BENCHMARK_CASE(simple_questionmark_benchmark_reference_stdcpp_regex_search)
EXPECT_EQ(std::regex_search("adadaa", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(character_class_benchmark)
{
Regex<PosixExtended> re("[[:alpha:]]");
@ -302,10 +308,10 @@ BENCHMARK_CASE(character_class_benchmark)
EXPECT_EQ(re.search(haystack.characters(), m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(character_class_benchmark_reference_stdcpp_regex_search)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(character_class_benchmark_reference_stdcpp)
{
std::regex re("[[:alpha:]]");
std::cmatch m;
@ -316,9 +322,9 @@ BENCHMARK_CASE(character_class_benchmark_reference_stdcpp_regex_search)
EXPECT_EQ(std::regex_search(haystack.characters(), m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(escaped_char_questionmark_benchmark)
{
Regex<PosixExtended> re("This\\.?And\\.?That");
@ -330,10 +336,10 @@ BENCHMARK_CASE(escaped_char_questionmark_benchmark)
EXPECT_EQ(re.match("This..And..That", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(escaped_char_questionmark_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(escaped_char_questionmark_benchmark_reference_stdcpp)
{
std::regex re("This\\.?And\\.?That");
std::cmatch m;
@ -344,9 +350,9 @@ BENCHMARK_CASE(escaped_char_questionmark_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("This..And..That", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(char_qualifier_asterisk_benchmark)
{
Regex<PosixExtended> re("regex*");
@ -356,10 +362,10 @@ BENCHMARK_CASE(char_qualifier_asterisk_benchmark)
EXPECT_EQ(re.search("#include <stdio.h>", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(char_qualifier_asterisk_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(char_qualifier_asterisk_benchmark_reference_stdcpp)
{
std::regex re("regex*");
std::cmatch m;
@ -368,9 +374,9 @@ BENCHMARK_CASE(char_qualifier_asterisk_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_search("#include <stdio.h>", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(parens_qualifier_questionmark_benchmark)
{
Regex<PosixExtended> re("test(hello)?test");
@ -381,10 +387,10 @@ BENCHMARK_CASE(parens_qualifier_questionmark_benchmark)
EXPECT_EQ(re.match("testasfdtest", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_questionmark_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_questionmark_benchmark_reference_stdcpp)
{
std::regex re("test(hello)?test");
std::cmatch m;
@ -394,9 +400,9 @@ BENCHMARK_CASE(parens_qualifier_questionmark_benchmark_reference_stdcpp_regex_ma
EXPECT_EQ(std::regex_match("testasfdtest", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(parens_qualifier_asterisk_benchmark)
{
Regex<PosixExtended> re("test(hello)*test");
@ -408,10 +414,10 @@ BENCHMARK_CASE(parens_qualifier_asterisk_benchmark)
EXPECT_EQ(re.match("aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbb", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_asterisk_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_asterisk_benchmark_reference_stdcpp)
{
std::regex re("test(hello)*test");
std::cmatch m;
@ -422,9 +428,9 @@ BENCHMARK_CASE(parens_qualifier_asterisk_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbb", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(parens_qualifier_asterisk_2_benchmark)
{
Regex<PosixExtended> re("test(.*)test");
@ -436,10 +442,10 @@ BENCHMARK_CASE(parens_qualifier_asterisk_2_benchmark)
EXPECT_EQ(re.match("aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbb", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_asterisk_2_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_asterisk_2_benchmark_reference_stdcpp)
{
std::regex re("test(.*)test");
std::cmatch m;
@ -450,9 +456,9 @@ BENCHMARK_CASE(parens_qualifier_asterisk_2_benchmark_reference_stdcpp_regex_matc
EXPECT_EQ(std::regex_match("aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbb", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(multi_parens_qualifier_questionmark_benchmark)
{
Regex<PosixExtended> re("test(a)?(b)?(c)?test");
@ -466,10 +472,10 @@ BENCHMARK_CASE(multi_parens_qualifier_questionmark_benchmark)
EXPECT_EQ(re.match("whaaaaat", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(multi_parens_qualifier_questionmark_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(multi_parens_qualifier_questionmark_benchmark_reference_stdcpp)
{
std::regex re("test(a)?(b)?(c)?test");
std::cmatch m;
@ -482,9 +488,9 @@ BENCHMARK_CASE(multi_parens_qualifier_questionmark_benchmark_reference_stdcpp_re
EXPECT_EQ(std::regex_match("whaaaaat", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_alternative_benchmark)
{
Regex<PosixExtended> re("test|hello|friends");
@ -496,10 +502,10 @@ BENCHMARK_CASE(simple_alternative_benchmark)
EXPECT_EQ(re.match("whaaaaat", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_alternative_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_alternative_benchmark_reference_stdcpp)
{
std::regex re("test|hello|friends");
std::cmatch m;
@ -510,9 +516,9 @@ BENCHMARK_CASE(simple_alternative_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("whaaaaat", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(alternative_match_groups_benchmark)
{
Regex<PosixExtended> re("test(a)?(b)?|hello ?(dear|my)? friends");
@ -528,10 +534,10 @@ BENCHMARK_CASE(alternative_match_groups_benchmark)
EXPECT_EQ(re.match("hello test friends", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(alternative_match_groups_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(alternative_match_groups_benchmark_reference_stdcpp)
{
std::regex re("test(a)?(b)?|hello ?(dear|my)? friends");
std::cmatch m;
@ -546,9 +552,9 @@ BENCHMARK_CASE(alternative_match_groups_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("hello test friends", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(parens_qualifier_exact_benchmark)
{
Regex<PosixExtended> re("(hello){3}");
@ -560,10 +566,10 @@ BENCHMARK_CASE(parens_qualifier_exact_benchmark)
EXPECT_EQ(re.search("test hellohellohello", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_exact_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_exact_benchmark_reference_stdcpp)
{
std::regex re("(hello){3}");
std::cmatch m;
@ -574,9 +580,9 @@ BENCHMARK_CASE(parens_qualifier_exact_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_search("test hellohellohello", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(parens_qualifier_minimum_benchmark)
{
Regex<PosixExtended> re("(hello){3,}");
@ -589,10 +595,10 @@ BENCHMARK_CASE(parens_qualifier_minimum_benchmark)
EXPECT_EQ(re.search("test hellohellohellohello", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_minimum_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_minimum_benchmark_reference_stdcpp)
{
std::regex re("(hello){3,}");
std::cmatch m;
@ -604,9 +610,9 @@ BENCHMARK_CASE(parens_qualifier_minimum_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_search("test hellohellohellohello", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(parens_qualifier_maximum_benchmark)
{
Regex<PosixExtended> re("(hello){2,3}");
@ -621,10 +627,10 @@ BENCHMARK_CASE(parens_qualifier_maximum_benchmark)
EXPECT_EQ(re.search("test hellohellohellohello", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_maximum_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(parens_qualifier_maximum_benchmark_reference_stdcpp)
{
std::regex re("(hello){2,3}");
std::cmatch m;
@ -638,9 +644,9 @@ BENCHMARK_CASE(parens_qualifier_maximum_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_search("test hellohellohellohello", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(char_qualifier_min_max_benchmark)
{
Regex<PosixExtended> re("c{3,30}");
@ -654,10 +660,10 @@ BENCHMARK_CASE(char_qualifier_min_max_benchmark)
EXPECT_EQ(re.match("cccccccccccccccccccccccccccccccc", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(char_qualifier_min_max_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(char_qualifier_min_max_benchmark_reference_stdcpp)
{
std::regex re("c{3,30}");
std::cmatch m;
@ -670,9 +676,9 @@ BENCHMARK_CASE(char_qualifier_min_max_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("cccccccccccccccccccccccccccccccc", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_bracket_chars_benchmark)
{
Regex<PosixExtended> re("[abc]");
@ -685,10 +691,10 @@ BENCHMARK_CASE(simple_bracket_chars_benchmark)
EXPECT_EQ(re.match("e", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_chars_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_chars_benchmark_reference_stdcpp)
{
std::regex re("[abc]");
std::cmatch m;
@ -700,9 +706,9 @@ BENCHMARK_CASE(simple_bracket_chars_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("e", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_bracket_chars_inverse_benchmark)
{
Regex<PosixExtended> re("[^abc]");
@ -715,10 +721,10 @@ BENCHMARK_CASE(simple_bracket_chars_inverse_benchmark)
EXPECT_EQ(re.match("e", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_chars_inverse_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_chars_inverse_benchmark_reference_stdcpp)
{
std::regex re("[^abc]");
std::cmatch m;
@ -730,9 +736,9 @@ BENCHMARK_CASE(simple_bracket_chars_inverse_benchmark_reference_stdcpp_regex_mat
EXPECT_EQ(std::regex_match("e", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_bracket_chars_range_benchmark)
{
Regex<PosixExtended> re("[a-d]");
@ -745,10 +751,10 @@ BENCHMARK_CASE(simple_bracket_chars_range_benchmark)
EXPECT_EQ(re.match("e", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_chars_range_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_chars_range_benchmark_reference_stdcpp)
{
std::regex re("[a-d]");
std::cmatch m;
@ -760,9 +766,9 @@ BENCHMARK_CASE(simple_bracket_chars_range_benchmark_reference_stdcpp_regex_match
EXPECT_EQ(std::regex_match("e", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_bracket_chars_range_inverse_benchmark)
{
Regex<PosixExtended> re("[^a-df-z]");
@ -777,10 +783,10 @@ BENCHMARK_CASE(simple_bracket_chars_range_inverse_benchmark)
EXPECT_EQ(re.match("z", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_chars_range_inverse_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_chars_range_inverse_benchmark_reference_stdcpp)
{
std::regex re("[^a-df-z]");
std::cmatch m;
@ -794,9 +800,9 @@ BENCHMARK_CASE(simple_bracket_chars_range_inverse_benchmark_reference_stdcpp_reg
EXPECT_EQ(std::regex_match("z", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(bracket_character_class_uuid_benchmark)
{
Regex<PosixExtended> re("^([[:xdigit:]]{8})-([[:xdigit:]]{4})-([[:xdigit:]]{4})-([[:xdigit:]]{4})-([[:xdigit:]]{12})$");
@ -806,10 +812,10 @@ BENCHMARK_CASE(bracket_character_class_uuid_benchmark)
EXPECT_EQ(re.match("fb9b62a2", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(bracket_character_class_uuid_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(bracket_character_class_uuid_benchmark_reference_stdcpp)
{
std::regex re("^([[:xdigit:]]{8})-([[:xdigit:]]{4})-([[:xdigit:]]{4})-([[:xdigit:]]{4})-([[:xdigit:]]{12})$");
std::cmatch m;
@ -818,9 +824,9 @@ BENCHMARK_CASE(bracket_character_class_uuid_benchmark_reference_stdcpp_regex_mat
EXPECT_EQ(std::regex_match("fb9b62a2", m, re), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_bracket_character_class_inverse_benchmark)
{
Regex<PosixExtended> re("[^[:digit:]]");
@ -833,10 +839,10 @@ BENCHMARK_CASE(simple_bracket_character_class_inverse_benchmark)
EXPECT_EQ(re.match("e", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_character_class_inverse_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_bracket_character_class_inverse_benchmark_reference_stdcpp)
{
std::regex re("[^[:digit:]]");
std::cmatch m;
@ -848,9 +854,9 @@ BENCHMARK_CASE(simple_bracket_character_class_inverse_benchmark_reference_stdcpp
EXPECT_EQ(std::regex_match("e", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(email_address_benchmark)
{
Regex<PosixExtended> re("^[A-Z0-9a-z._%+-]{1,64}@(?:[A-Za-z0-9-]{1,63}\\.){1,125}[A-Za-z]{2,63}$");
@ -860,10 +866,10 @@ BENCHMARK_CASE(email_address_benchmark)
EXPECT_EQ(re.match("this.is.a.very_long_email_address@world.wide.web", m), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(email_address_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(email_address_benchmark_reference_stdcpp)
{
std::regex re("^[A-Z0-9a-z._%+-]{1,64}@(?:[A-Za-z0-9-]{1,63}\\.){1,125}[A-Za-z]{2,63}$");
std::cmatch m;
@ -872,9 +878,9 @@ BENCHMARK_CASE(email_address_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_match("this.is.a.very_long_email_address@world.wide.web", m, re), true);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OUR)
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_ignorecase_benchmark)
{
Regex<PosixExtended> re("^hello friends", PosixFlags::Insensitive);
@ -890,10 +896,10 @@ BENCHMARK_CASE(simple_ignorecase_benchmark)
EXPECT_EQ(re.search("hell Friends", m), false);
}
}
#endif
# endif
#if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_ignorecase_benchmark_reference_stdcpp_regex_match)
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_ignorecase_benchmark_reference_stdcpp)
{
std::regex re("^hello friends", std::regex_constants::icase);
std::cmatch m;
@ -908,7 +914,78 @@ BENCHMARK_CASE(simple_ignorecase_benchmark_reference_stdcpp_regex_match)
EXPECT_EQ(std::regex_search("hell Friends", m, re), false);
}
}
#endif
# endif
# if defined(REGEX_BENCHMARK_OUR)
BENCHMARK_CASE(simple_notbol_noteol_benchmark)
{
String pattern = "^hello friends$";
String pattern2 = "hello friends";
regex_t regex, regex2;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR);
EXPECT_EQ(regcomp(&regex2, pattern2.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR);
for (size_t i = 0; i < BENCHMARK_LOOP_ITERATIONS; ++i) {
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTBOL | REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends", 0, NULL, REG_NOTBOL | REG_SEARCH), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_SEARCH), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends b", 0, NULL, REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends b", 0, NULL, REG_NOTEOL | REG_SEARCH), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTEOL | REG_SEARCH), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL | REG_SEARCH), REG_NOMATCH);
EXPECT_EQ(regexec(&regex2, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex2, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH);
}
regfree(&regex);
}
# endif
# if defined(REGEX_BENCHMARK_OTHER)
BENCHMARK_CASE(simple_notbol_noteol_benchmark_reference_stdcpp)
{
std::regex re1("^hello friends$", std::regex_constants::match_not_bol);
std::regex re2("^hello friends$", std::regex_constants::match_not_eol);
std::regex re3("^hello friends$", std::regex_constants::match_not_bol | std::regex_constants::match_not_eol);
std::regex re4("hello friends", std::regex_constants::match_not_bol);
std::regex re5("hello friends", std::regex_constants::match_not_eol);
std::cmatch m;
for (size_t i = 0; i < BENCHMARK_LOOP_ITERATIONS; ++i) {
EXPECT_EQ(std::regex_match("hello friends", m, re1), false);
EXPECT_EQ(std::regex_match("hello friends", m, re2), false);
EXPECT_EQ(std::regex_match("hello friends", m, re3), false);
EXPECT_EQ(std::regex_match("a hello friends b", m, re1), false);
EXPECT_EQ(std::regex_match("a hello friends", m, re1), false);
EXPECT_EQ(std::regex_search("a hello friends", m, re1), true);
EXPECT_EQ(std::regex_search("a hello friends b", m, re1), true);
EXPECT_EQ(std::regex_match("a hello friends b", m, re2), false);
EXPECT_EQ(std::regex_match("hello friends b", m, re2), false);
EXPECT_EQ(std::regex_search("hello friends b", m, re2), true);
EXPECT_EQ(std::regex_search("a hello friends b", m, re2), false);
EXPECT_EQ(std::regex_match("a hello friends b", m, re3), false);
EXPECT_EQ(std::regex_search("a hello friends b", m, re3), false);
EXPECT_EQ(std::regex_match("hello friends", m, re4), false);
EXPECT_EQ(std::regex_match("hello friends", m, re5), false);
}
}
# endif
#endif
TEST_MAIN(Regex)

View file

@ -383,7 +383,7 @@ TEST_CASE(ini_file_entries)
#endif
EXPECT_EQ(result.matches.at(0).view, "[Window]");
EXPECT_EQ(result.capture_group_matches.at(0).at(1).view, "Window");
EXPECT_EQ(result.capture_group_matches.at(0).at(0).view, "Window");
EXPECT_EQ(result.matches.at(1).view, "Opacity=255");
EXPECT_EQ(result.matches.at(1).line, 1u);
EXPECT_EQ(result.matches.at(1).column, 0u);
@ -396,6 +396,20 @@ TEST_CASE(ini_file_entries)
EXPECT_EQ(result.capture_group_matches.at(2).at(0).column, 12u);
}
TEST_CASE(ini_file_entries2)
{
Regex<PosixExtended> re("[[:alpha:]]*=([[:digit:]]*)");
RegexResult result;
String haystack = "ViewMode=Icon";
EXPECT_EQ(re.match(haystack.view(), result), false);
EXPECT_EQ(result.count, 0u);
EXPECT_EQ(re.search(haystack.view(), result), true);
EXPECT_EQ(result.count, 1u);
}
TEST_CASE(named_capture_group)
{
Regex<PosixExtended> re("[[:alpha:]]*=(?<Test>[[:digit:]]*)");

View file

@ -30,13 +30,6 @@
#include <LibC/regex.h>
#include <stdio.h>
#define BENCHMARK_LOOP_ITERATIONS 100000
#define DISABLE_REGEX_BENCHMARK
//#if not(defined(REGEX_DEBUG) || defined(REGEX_MATCH_STATUS) || defined(DISABLE_REGEX_BENCHMARK))
# include <regex>
//#endif
TEST_CASE(catch_all)
{
String pattern = "^.*$";
@ -1115,9 +1108,11 @@ TEST_CASE(simple_ignorecase)
TEST_CASE(simple_notbol_noteol)
{
String pattern = "^hello friends$";
regex_t regex;
String pattern2 = "hello friends";
regex_t regex, regex2;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR);
EXPECT_EQ(regcomp(&regex2, pattern2.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH);
@ -1136,76 +1131,10 @@ TEST_CASE(simple_notbol_noteol)
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL | REG_SEARCH), REG_NOMATCH);
pattern = "hello friends";
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex2, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex2, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH);
regfree(&regex);
}
//#if not(defined(REGEX_DEBUG) || defined(REGEX_MATCH_STATUS) || defined(DISABLE_REGEX_BENCHMARK))
//BENCHMARK_CASE(simple_notbol_noteol_benchmark)
//{
// String pattern = "^hello friends$";
// regex_t regex;
// EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR);
// for (size_t i = 0; i < BENCHMARK_LOOP_ITERATIONS; ++i) {
// EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTBOL | REG_NOTEOL), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "a hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "a hello friends", 0, NULL, REG_NOTBOL | REG_SEARCH), REG_NOERR);
// EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_SEARCH), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTEOL), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "hello friends b", 0, NULL, REG_NOTEOL), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "hello friends b", 0, NULL, REG_NOTEOL | REG_SEARCH), REG_NOERR);
// EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTEOL | REG_SEARCH), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL), REG_NOMATCH);
// EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL | REG_SEARCH), REG_NOERR);
// }
// regfree(&regex);
//}
BENCHMARK_CASE(simple_notbol_noteol_benchmark_reference_stdcpp_regex_match)
{
std::regex re1("^hello friends$", std::regex_constants::match_not_bol);
std::regex re2("^hello friends$", std::regex_constants::match_not_eol);
std::regex re3("^hello friends$", std::regex_constants::match_not_bol | std::regex_constants::match_not_eol);
std::regex re4("hello friends", std::regex_constants::match_not_bol);
std::regex re5("hello friends", std::regex_constants::match_not_eol);
std::cmatch m;
//for (size_t i = 0; i < BENCHMARK_LOOP_ITERATIONS; ++i) {
EXPECT_EQ(std::regex_match("hello friends", m, re1), false);
EXPECT_EQ(std::regex_match("hello friends", m, re2), false);
EXPECT_EQ(std::regex_match("hello friends", m, re3), false);
EXPECT_EQ(std::regex_match("a hello friends b", m, re1), false);
EXPECT_EQ(std::regex_match("a hello friends", m, re1), false);
EXPECT_EQ(std::regex_search("a hello friends", m, re1), true);
EXPECT_EQ(std::regex_search("a hello friends b", m, re1), true);
EXPECT_EQ(std::regex_match("a hello friends b", m, re2), false);
EXPECT_EQ(std::regex_match("hello friends b", m, re2), false);
EXPECT_EQ(std::regex_search("hello friends b", m, re2), true);
EXPECT_EQ(std::regex_search("a hello friends b", m, re2), false);
EXPECT_EQ(std::regex_match("a hello friends b", m, re3), false);
EXPECT_EQ(std::regex_search("a hello friends b", m, re3), false);
EXPECT_EQ(std::regex_match("hello friends", m, re4), false);
EXPECT_EQ(std::regex_match("hello friends", m, re5), false);
//}
}
//#endif
TEST_MAIN(Regex)