diff --git a/src/logdata/include/data/hsregularexpression.h b/src/logdata/include/data/hsregularexpression.h index 060f357e2..56aa8a0a4 100644 --- a/src/logdata/include/data/hsregularexpression.h +++ b/src/logdata/include/data/hsregularexpression.h @@ -39,6 +39,9 @@ #include "regularexpressionpattern.h" +using MatchedPatterns = robin_hood::unordered_flat_map; +using MatchingResult = std::variant; + class DefaultRegularExpressionMatcher { public: explicit DefaultRegularExpressionMatcher( @@ -60,14 +63,18 @@ class DefaultRegularExpressionMatcher { return matchingPatterns; } - robin_hood::unordered_flat_map match( const std::string_view& utf8Data ) const + MatchingResult match( const std::string_view& utf8Data ) const { - robin_hood::unordered_flat_map matchingPatterns; + MatchedPatterns matchingPatterns; for ( const auto& regexp : regexp_ ) { const auto hasMatch = regexp.second .match( QString::fromUtf8( utf8Data.data(), static_cast( utf8Data.size() ) ) ) .hasMatch(); + if ( regexp_.size() == 1 ) { + return hasMatch; + } + matchingPatterns.emplace( regexp.first, hasMatch ); } return matchingPatterns; @@ -93,7 +100,7 @@ class HsMatcher { HsMatcher( HsMatcher&& other ) = default; HsMatcher& operator=( HsMatcher&& other ) = default; - robin_hood::unordered_map match( const std::string_view& utf8Data ) const; + MatchingResult match( const std::string_view& utf8Data ) const; private: HsDatabase database_; diff --git a/src/logdata/include/data/regularexpression.h b/src/logdata/include/data/regularexpression.h index 9f9ce110a..a0d20eeef 100644 --- a/src/logdata/include/data/regularexpression.h +++ b/src/logdata/include/data/regularexpression.h @@ -26,8 +26,6 @@ #include - - #include "hsregularexpression.h" class PatternMatcher; @@ -35,7 +33,7 @@ class BooleanExpressionEvaluator; class RegularExpression { public: - RegularExpression( const RegularExpressionPattern& pattern); + RegularExpression( const RegularExpressionPattern& pattern ); std::unique_ptr createMatcher() const; @@ -44,6 +42,7 @@ class RegularExpression { private: bool isInverse_ = false; + bool isBooleanCombination_ = false; QString expression_; std::vector subPatterns_; @@ -68,6 +67,10 @@ class PatternMatcher { private: bool isInverse_ = false; + bool isBooleanCombination_ = false; + + std::string mainPatternId_; + MatcherVariant matcher_; std::unique_ptr evaluator_; diff --git a/src/logdata/src/hsregularexpression.cpp b/src/logdata/src/hsregularexpression.cpp index 2c89adb7b..a4f1bf753 100644 --- a/src/logdata/src/hsregularexpression.cpp +++ b/src/logdata/src/hsregularexpression.cpp @@ -33,6 +33,7 @@ namespace { struct MatcherContext { const std::vector& patternIds; robin_hood::unordered_flat_set& matchingPatterns; + bool hasMatch = false; }; int matchCallback( unsigned int id, unsigned long long from, unsigned long long to, @@ -42,10 +43,15 @@ int matchCallback( unsigned int id, unsigned long long from, unsigned long long Q_UNUSED( to ); Q_UNUSED( flags ); - MatcherContext* matchResult = static_cast( context ); + MatcherContext* matchContext = static_cast( context ); - const auto& patternId = matchResult->patternIds[ id ]; - matchResult->matchingPatterns.insert( patternId ); + if ( matchContext->patternIds.size() == 1 ) { + matchContext->hasMatch = true; + } + else { + const auto& patternId = matchContext->patternIds[ id ]; + matchContext->matchingPatterns.insert( patternId ); + } return 0; } @@ -59,29 +65,33 @@ HsMatcher::HsMatcher( HsDatabase db, HsScratch scratch, const std::vector HsMatcher::match( const std::string_view& utf8Data ) const +MatchingResult HsMatcher::match( const std::string_view& utf8Data ) const { - robin_hood::unordered_flat_set matchingPatterns; if ( !scratch_ || !database_ ) { return {}; } - + robin_hood::unordered_flat_set matchingPatterns; + MatcherContext context{ patternIds_, matchingPatterns }; - hs_scan( database_.get(), utf8Data.data(), static_cast( utf8Data.size() ), 0, scratch_.get(), matchCallback, static_cast( &context ) ); - robin_hood::unordered_map results; - for ( const auto& patternId : patternIds_ ) { - results[ patternId ] = false; - } + if ( patternIds_.size() > 1 ) { + robin_hood::unordered_map results; + for ( const auto& patternId : patternIds_ ) { + results[ patternId ] = false; + } - for ( const auto& match : matchingPatterns ) { - results[ match ] = true; - } + for ( const auto& match : matchingPatterns ) { + results[ match ] = true; + } - return results; + return results; + } + else { + return context.hasMatch; + } } HsRegularExpression::HsRegularExpression( const RegularExpressionPattern& pattern ) diff --git a/src/logdata/src/regularexpression.cpp b/src/logdata/src/regularexpression.cpp index 22e2698cb..7c7aca206 100644 --- a/src/logdata/src/regularexpression.cpp +++ b/src/logdata/src/regularexpression.cpp @@ -27,6 +27,7 @@ #include "configuration.h" #include "log.h" +#include "overload_visitor.h" #include "uuid.h" #include "regularexpression.h" @@ -144,6 +145,7 @@ class BooleanExpressionEvaluator { RegularExpression::RegularExpression( const RegularExpressionPattern& pattern ) : isInverse_( pattern.isExclude ) + , isBooleanCombination_( pattern.isBoolean ) , expression_( pattern.pattern ) { try { @@ -190,6 +192,8 @@ std::unique_ptr RegularExpression::createMatcher() const PatternMatcher::PatternMatcher( const RegularExpression& expression ) : isInverse_( expression.isInverse_ ) + , isBooleanCombination_( expression.isBooleanCombination_ ) + , mainPatternId_( expression.subPatterns_.front().id() ) , matcher_( expression.hsExpression_.createMatcher() ) , evaluator_( std::make_unique( expression.expression_.toStdString(), expression.subPatterns_ ) ) @@ -214,9 +218,19 @@ bool PatternMatcher::hasMatchInternal( std::string_view line ) const const auto results = std::visit( [ &line ]( const auto& m ) { return m.match( line ); }, matcher_ ); - if ( results.size() == 1 ) { - return results.begin()->second; - } - - return evaluator_->evaluate( results ); + return std::visit( makeOverloadVisitor( + [ this ]( bool hasMatch ) { + if ( !isBooleanCombination_ ) { + return hasMatch; + } + else { + MatchedPatterns matchedPatterns; + matchedPatterns.emplace( mainPatternId_, hasMatch ); + return evaluator_->evaluate( matchedPatterns ); + } + }, + [ this ]( const MatchedPatterns& matchedPatterns ) { + return evaluator_->evaluate( matchedPatterns ); + } ), + results ); } \ No newline at end of file