From d18b89bceb3afa35e33395caf95dd4d5c98784bf Mon Sep 17 00:00:00 2001 From: Strahinja Val Markovic Date: Sun, 24 Jun 2012 17:58:20 -0700 Subject: [PATCH] Fixed another bug in the word boundary condition The problem was that should have been using a longest common subsequence algorithm for the "number of word boundary character matches" calculation. Our old approach would fail for the following case: Query: "caafoo" Candidate1 : "acaaCaaFooGxx" Candidate2 : "aCaafoog" Candidate1 needs to win. This is now also a test case. --- cpp/ycm/Result.cpp | 44 ++++++++++++++++++++++++-------- cpp/ycm/tests/Completer_test.cpp | 6 +++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/cpp/ycm/Result.cpp b/cpp/ycm/Result.cpp index 891f2084..8a83d1f2 100644 --- a/cpp/ycm/Result.cpp +++ b/cpp/ycm/Result.cpp @@ -19,6 +19,7 @@ #include "standard.h" #include "Utils.h" #include +#include using boost::algorithm::istarts_with; @@ -28,19 +29,42 @@ namespace YouCompleteMe namespace { +template< class T > +int LongestCommonSubsequenceLength(const T &first, const T &second) +{ + const T &longer = first.size() > second.size() ? first : second; + const T &shorter = first.size() > second.size() ? second : first; + + int longer_len = longer.size(); + int shorter_len = shorter.size(); + + std::vector previous( shorter_len + 1, 0 ); + std::vector current( shorter_len + 1, 0 ); + + for (int i = 0; i < longer_len; ++i ) + { + for (int j = 0; j < shorter_len; ++j ) + { + if ( longer[ i ] == shorter[ j ] ) + current[ j + 1 ] = previous[ j ] + 1; + else + current[ j + 1 ] = std::max( current[ j ], previous[ j + 1 ] ); + } + + for (int j = 0; j < shorter_len; ++j ) + { + previous[ j + 1 ] = current[ j + 1 ]; + } + } + + return current[ shorter_len ]; +} + + int NumWordBoundaryCharMatches( const std::string &query, const std::string &word_boundary_chars ) { - uint i = 0; - uint j = 0; - while ( j < query.size() && i < word_boundary_chars.size() ) - { - if ( toupper( query[ j ] ) == toupper( word_boundary_chars[ i ] ) ) - ++j; - ++i; - } - - return j; + return LongestCommonSubsequenceLength(query, word_boundary_chars); } } // unnamed namespace diff --git a/cpp/ycm/tests/Completer_test.cpp b/cpp/ycm/tests/Completer_test.cpp index ac9f1c7f..b33d2053 100644 --- a/cpp/ycm/tests/Completer_test.cpp +++ b/cpp/ycm/tests/Completer_test.cpp @@ -128,6 +128,12 @@ TEST( CompleterTest, RatioUtilizationTieBreak ) ElementsAre( "aFooBarQux", "afbq" ) ); + EXPECT_THAT( Completer( Candidates( + "acaaCaaFooGxx", + "aCaafoog" ) ).CandidatesForQuery( "caafoo" ), + ElementsAre( "acaaCaaFooGxx", + "aCaafoog" ) ); + EXPECT_THAT( Completer( Candidates( "FooBarQux", "FooBarQuxZaa" ) ).CandidatesForQuery( "fbq" ),