2012-04-15 23:28:46 -04:00
|
|
|
// Copyright (C) 2011, 2012 Strahinja Val Markovic <val@markovic.io>
|
2012-04-15 19:57:10 -04:00
|
|
|
//
|
|
|
|
// This file is part of YouCompleteMe.
|
|
|
|
//
|
|
|
|
// YouCompleteMe is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// YouCompleteMe is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#include "Result.h"
|
2012-05-06 03:01:32 -04:00
|
|
|
#include "standard.h"
|
2012-04-15 19:57:10 -04:00
|
|
|
#include "Utils.h"
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
|
|
|
|
using boost::algorithm::istarts_with;
|
|
|
|
|
|
|
|
namespace YouCompleteMe
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
2012-04-15 23:10:39 -04:00
|
|
|
int NumWordBoundaryCharMatches( const std::string &query,
|
2012-04-15 19:57:10 -04:00
|
|
|
const std::string &word_boundary_chars )
|
|
|
|
{
|
2012-05-06 03:01:32 -04:00
|
|
|
uint i = 0;
|
|
|
|
uint j = 0;
|
2012-04-15 23:10:39 -04:00
|
|
|
while ( j < query.size() && i < word_boundary_chars.size() )
|
2012-04-15 19:57:10 -04:00
|
|
|
{
|
2012-04-15 23:10:39 -04:00
|
|
|
if ( toupper( query[ j ] ) == toupper( word_boundary_chars[ i ] ) )
|
2012-06-24 18:11:58 -04:00
|
|
|
++j;
|
|
|
|
++i;
|
2012-04-15 19:57:10 -04:00
|
|
|
}
|
|
|
|
|
2012-06-24 18:11:58 -04:00
|
|
|
return j;
|
2012-04-15 19:57:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
} // unnamed namespace
|
|
|
|
|
|
|
|
|
|
|
|
Result::Result( bool is_subsequence )
|
|
|
|
:
|
|
|
|
is_subsequence_( is_subsequence ),
|
|
|
|
first_char_same_in_query_and_text_( false ),
|
|
|
|
ratio_of_word_boundary_chars_in_query_( 0 ),
|
|
|
|
word_boundary_char_utilization_( 0 ),
|
|
|
|
query_is_candidate_prefix_( false ),
|
2012-04-17 01:13:05 -04:00
|
|
|
text_is_lowercase_( false ),
|
2012-06-24 18:35:00 -04:00
|
|
|
char_match_index_sum_( 0 ),
|
2012-04-15 19:57:10 -04:00
|
|
|
text_( NULL )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Result::Result( bool is_subsequence,
|
|
|
|
const std::string *text,
|
2012-04-17 01:13:05 -04:00
|
|
|
bool text_is_lowercase,
|
2012-06-24 18:35:00 -04:00
|
|
|
int char_match_index_sum,
|
2012-04-15 19:57:10 -04:00
|
|
|
const std::string &word_boundary_chars,
|
|
|
|
const std::string &query )
|
|
|
|
:
|
|
|
|
is_subsequence_( is_subsequence ),
|
|
|
|
first_char_same_in_query_and_text_( false ),
|
|
|
|
ratio_of_word_boundary_chars_in_query_( 0 ),
|
|
|
|
word_boundary_char_utilization_( 0 ),
|
|
|
|
query_is_candidate_prefix_( false ),
|
2012-04-17 01:13:05 -04:00
|
|
|
text_is_lowercase_( text_is_lowercase ),
|
2012-06-24 18:35:00 -04:00
|
|
|
char_match_index_sum_( char_match_index_sum ),
|
2012-04-15 19:57:10 -04:00
|
|
|
text_( text )
|
|
|
|
{
|
|
|
|
if ( is_subsequence )
|
2012-04-17 01:13:05 -04:00
|
|
|
SetResultFeaturesFromQuery( word_boundary_chars, query );
|
2012-04-15 19:57:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-24 18:35:00 -04:00
|
|
|
// TODO: do we need a custom copy ctor?
|
2012-04-15 19:57:10 -04:00
|
|
|
Result::Result( const Result& other )
|
|
|
|
:
|
|
|
|
is_subsequence_( other.is_subsequence_ ),
|
|
|
|
first_char_same_in_query_and_text_(
|
|
|
|
other.first_char_same_in_query_and_text_ ),
|
|
|
|
ratio_of_word_boundary_chars_in_query_(
|
|
|
|
other.ratio_of_word_boundary_chars_in_query_ ),
|
|
|
|
word_boundary_char_utilization_( other.word_boundary_char_utilization_ ),
|
|
|
|
query_is_candidate_prefix_( other.query_is_candidate_prefix_ ),
|
2012-04-17 01:13:05 -04:00
|
|
|
text_is_lowercase_( other.text_is_lowercase_ ),
|
2012-06-24 18:35:00 -04:00
|
|
|
char_match_index_sum_( other.char_match_index_sum_ ),
|
2012-04-15 19:57:10 -04:00
|
|
|
text_( other.text_ )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Result::operator< ( const Result &other ) const {
|
|
|
|
// Yes, this is ugly but it also needs to be fast. Since this is called a
|
|
|
|
// bazillion times, we have to make sure only the required comparisons are
|
|
|
|
// made, and no more.
|
|
|
|
|
|
|
|
if ( first_char_same_in_query_and_text_ !=
|
|
|
|
other.first_char_same_in_query_and_text_ )
|
|
|
|
{
|
|
|
|
return first_char_same_in_query_and_text_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool equal_wb_ratios = AlmostEqual(
|
|
|
|
ratio_of_word_boundary_chars_in_query_,
|
|
|
|
other.ratio_of_word_boundary_chars_in_query_ );
|
|
|
|
|
|
|
|
bool equal_wb_utilization = AlmostEqual(
|
|
|
|
word_boundary_char_utilization_,
|
|
|
|
other.word_boundary_char_utilization_ );
|
|
|
|
|
|
|
|
if ( AlmostEqual( ratio_of_word_boundary_chars_in_query_, 1.0 ) ||
|
|
|
|
AlmostEqual( other.ratio_of_word_boundary_chars_in_query_, 1.0 ) )
|
|
|
|
{
|
|
|
|
if ( !equal_wb_ratios )
|
|
|
|
{
|
|
|
|
return ratio_of_word_boundary_chars_in_query_ >
|
|
|
|
other.ratio_of_word_boundary_chars_in_query_;
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( !equal_wb_utilization )
|
|
|
|
return word_boundary_char_utilization_ >
|
|
|
|
other.word_boundary_char_utilization_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( query_is_candidate_prefix_ != other.query_is_candidate_prefix_ )
|
|
|
|
return query_is_candidate_prefix_;
|
|
|
|
|
|
|
|
if ( !equal_wb_ratios )
|
|
|
|
{
|
|
|
|
return ratio_of_word_boundary_chars_in_query_ >
|
|
|
|
other.ratio_of_word_boundary_chars_in_query_;
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( !equal_wb_utilization )
|
|
|
|
return word_boundary_char_utilization_ >
|
|
|
|
other.word_boundary_char_utilization_;
|
|
|
|
}
|
|
|
|
|
2012-06-24 18:35:00 -04:00
|
|
|
if ( char_match_index_sum_ != other.char_match_index_sum_ )
|
|
|
|
return char_match_index_sum_ < other.char_match_index_sum_;
|
|
|
|
|
2012-04-15 19:57:10 -04:00
|
|
|
if ( text_->length() != other.text_->length() )
|
|
|
|
return text_->length() < other.text_->length();
|
2012-04-17 01:13:05 -04:00
|
|
|
|
|
|
|
if ( text_is_lowercase_ != other.text_is_lowercase_ )
|
|
|
|
return text_is_lowercase_;
|
2012-04-15 19:57:10 -04:00
|
|
|
|
|
|
|
return *text_ < *other.text_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Result::SetResultFeaturesFromQuery(
|
2012-04-17 01:13:05 -04:00
|
|
|
const std::string &word_boundary_chars,
|
|
|
|
const std::string &query)
|
2012-04-15 19:57:10 -04:00
|
|
|
{
|
|
|
|
if ( query.empty() || text_->empty() )
|
|
|
|
return;
|
|
|
|
|
2012-04-15 23:10:39 -04:00
|
|
|
first_char_same_in_query_and_text_ =
|
|
|
|
toupper( query[ 0 ] ) == toupper( (*text_)[ 0 ] );
|
|
|
|
int num_wb_matches = NumWordBoundaryCharMatches( query,
|
2012-04-15 19:57:10 -04:00
|
|
|
word_boundary_chars );
|
|
|
|
ratio_of_word_boundary_chars_in_query_ =
|
|
|
|
num_wb_matches / static_cast< double >( query.length() );
|
|
|
|
word_boundary_char_utilization_ =
|
|
|
|
num_wb_matches / static_cast< double >( word_boundary_chars.length() );
|
|
|
|
query_is_candidate_prefix_ = istarts_with( *text_, query );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace YouCompleteMe
|