Improving IdentifierCompleter performance

We limit the number of candidates returned to Vim to 20 and also make sure that
we are not returning any duplicate candidates. This provides a noticeable
improvement in latency.
This commit is contained in:
Strahinja Val Markovic 2012-07-21 12:06:18 -07:00
parent 0f7f32d96f
commit 7bf18c7c5c
6 changed files with 40 additions and 4 deletions

View File

@ -43,6 +43,13 @@ CandidateRepository& CandidateRepository::Instance()
} }
int CandidateRepository::NumStoredCandidates()
{
boost::lock_guard< boost::mutex > locker( holder_mutex_ );
return candidate_holder_.size();
}
std::vector< const Candidate* > CandidateRepository::GetCandidatesForStrings( std::vector< const Candidate* > CandidateRepository::GetCandidatesForStrings(
const std::vector< std::string > &strings ) const std::vector< std::string > &strings )
{ {

View File

@ -39,6 +39,8 @@ class CandidateRepository : boost::noncopyable
public: public:
static CandidateRepository& Instance(); static CandidateRepository& Instance();
int NumStoredCandidates();
std::vector< const Candidate* > GetCandidatesForStrings( std::vector< const Candidate* > GetCandidatesForStrings(
const std::vector< std::string > &strings ); const std::vector< std::string > &strings );

View File

@ -128,6 +128,8 @@ bool IsChunkKindForExtraMenuInfo( CXCompletionChunkKind kind )
char CursorKindToVimKind( CXCursorKind kind ) char CursorKindToVimKind( CXCursorKind kind )
{ {
// TODO: actually it appears that Vim will show returned kinds even when they
// do not match the "approved" list, so let's use that
switch ( kind ) switch ( kind )
{ {
case CXCursor_UnexposedDecl: case CXCursor_UnexposedDecl:

View File

@ -21,6 +21,7 @@
#include "Candidate.h" #include "Candidate.h"
#include "Utils.h" #include "Utils.h"
#include <boost/unordered_set.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
#include <algorithm> #include <algorithm>
@ -173,11 +174,19 @@ void IdentifierCompleter::ResultsForQueryAndType(
Bitset query_bitset = LetterBitsetFromString( query ); Bitset query_bitset = LetterBitsetFromString( query );
boost::unordered_set< const Candidate* > seen_candidates;
seen_candidates.reserve( candidate_repository_.NumStoredCandidates() );
foreach ( const FilepathToCandidates::value_type &path_and_candidates, foreach ( const FilepathToCandidates::value_type &path_and_candidates,
*it->second ) *it->second )
{ {
foreach ( const Candidate* candidate, *path_and_candidates.second ) foreach ( const Candidate* candidate, *path_and_candidates.second )
{ {
if ( ContainsKey( seen_candidates, candidate ) )
continue;
else
seen_candidates.insert( candidate );
if ( !candidate->MatchesQueryBitset( query_bitset ) ) if ( !candidate->MatchesQueryBitset( query_bitset ) )
continue; continue;

View File

@ -73,6 +73,15 @@ TEST( IdentifierCompleterTest, EmptyQueryNoResults )
ElementsAre() ); ElementsAre() );
} }
TEST( IdentifierCompleterTest, NoDuplicatesReturned )
{
EXPECT_THAT( IdentifierCompleter( Candidates(
"foobar",
"foobar",
"foobar" ) ).CandidatesForQuery( "foo" ),
ElementsAre( "foobar" ) );
}
TEST( IdentifierCompleterTest, OneCandidate ) TEST( IdentifierCompleterTest, OneCandidate )
{ {

View File

@ -21,8 +21,10 @@ import re
import vim import vim
import indexer import indexer
min_num_chars = int( vim.eval( "g:ycm_min_num_of_chars_for_completion" ) ) MIN_NUM_CHARS = int( vim.eval( "g:ycm_min_num_of_chars_for_completion" ) )
clang_filetypes = set( [ 'c', 'cpp', 'objc', 'objcpp' ] ) CLANG_FILETYPES = set( [ 'c', 'cpp', 'objc', 'objcpp' ] )
MAX_IDENTIFIER_COMPLETIONS_RETURNED = 20
class Completer( object ): class Completer( object ):
def __init__( self ): def __init__( self ):
@ -89,6 +91,11 @@ class IdentifierCompleter( Completer ):
filepath, filepath,
True ) True )
def CandidatesFromStoredRequest( self ):
if not self.future:
return []
return self.future.GetResults()[ : MAX_IDENTIFIER_COMPLETIONS_RETURNED ]
class ClangCompleter( Completer ): class ClangCompleter( Completer ):
def __init__( self ): def __init__( self ):
@ -181,7 +188,7 @@ def CurrentLineAndColumn():
def ShouldUseClang( start_column ): def ShouldUseClang( start_column ):
filetype = vim.eval( "&filetype" ) filetype = vim.eval( "&filetype" )
if filetype not in clang_filetypes: if filetype not in CLANG_FILETYPES:
return False return False
line = vim.current.line line = vim.current.line
@ -253,7 +260,7 @@ def PreviousIdentifier():
while start_column > 0 and IsIdentifierChar( line[ start_column - 1 ] ): while start_column > 0 and IsIdentifierChar( line[ start_column - 1 ] ):
start_column -= 1 start_column -= 1
if end_column - start_column < min_num_chars: if end_column - start_column < MIN_NUM_CHARS:
return "" return ""
return line[ start_column : end_column ] return line[ start_column : end_column ]