17#define UI_MENU_ARROW_SEP BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE
18#define UI_MENU_ARROW_SEP_UNICODE 0x25b8
29 constexpr int deletion_cost = 1;
30 constexpr int insertion_cost = 1;
31 constexpr int substitution_cost = 1;
32 constexpr int transposition_cost = 1;
41 const int row_length = size_b + 1;
51 v1[i] = i * insertion_cost;
57 v2[0] = (i + 1) * deletion_cost;
68 int new_cost = std::min({v1[j + 1] + deletion_cost,
69 v2[j] + insertion_cost,
70 v1[j] + (unicode_a != unicode_b) * substitution_cost});
72 if (unicode_a == prev_unicode_b && prev_unicode_a == unicode_b) {
73 new_cost = std::min(new_cost, v0[j - 1] + transposition_cost);
78 prev_unicode_b = unicode_b;
84 prev_unicode_a = unicode_a;
101 if (query_size == 1) {
107 const int max_errors = query_size <= 1 ? 0 : query_size / 8 + 1;
110 if (query_size - full_size > max_errors) {
118 const char *full_begin = full.begin();
119 const char *full_end = full.end();
121 const char *window_begin = full_begin;
122 const char *window_end = window_begin;
123 const int window_size = std::min(query_size + max_errors, full_size);
124 const int extra_chars = window_size - query_size;
125 const int max_acceptable_distance = max_errors + extra_chars;
127 for (
int i = 0; i < window_size; i++) {
132 StringRef window{window_begin, window_end};
137 if (
ELEM(window_begin_unicode, query_first_unicode, query_second_unicode)) {
139 if (distance <= max_acceptable_distance) {
143 if (window_end == full_end) {
149 const int window_offset = std::max(1, distance / 2);
150 for (
int i = 0; i < window_offset && window_end < full_end; i++) {
192 if (start >= words.
size()) {
198 size_t query_index = 0;
199 int word_index = start;
200 size_t char_index = 0;
202 int first_found_word_index = -1;
204 while (query_index < query.
size()) {
206 query.
data(), query.
size(), &query_index);
209 if (word_index >= words.
size()) {
210 if (first_found_word_index >= 0) {
227 if (
int(char_index) < word.
size()) {
229 word.
data(), word.
size(), &char_index);
230 if (query_unicode == char_unicode) {
232 if (first_found_word_index == -1) {
233 first_found_word_index = word_index;
246 query, item, word_match_map, first_found_word_index + 1))
248 if (sub_match->better_than(match, item)) {
275 bool use_shortest_match =
false;
276 for (
const StringRef other_word : remaining_query_words) {
277 if (other_word.startswith(query)) {
278 use_shortest_match =
true;
284 int best_word_index = -1;
285 bool best_word_in_main_group =
false;
293 bool found_new_best =
false;
294 if (use_shortest_match) {
295 if (word.
size() < best_word_size) {
296 found_new_best =
true;
300 if (!best_word_in_main_group) {
301 found_new_best =
true;
304 if (found_new_best) {
306 best_word_size = word.
size();
307 best_word_in_main_group = word_in_main_group;
311 return best_word_index;
325 if (error_count >= 0) {
326 *r_error_count = error_count;
347 for (
const int query_word_index : query_words.
index_range()) {
348 const StringRef query_word = query_words[query_word_index];
352 query_word, item, word_match_map, query_words.
drop_front(query_word_index + 1));
353 if (word_index >= 0) {
356 total_match_score += is_main_group ? 10 : 9;
357 word_match_map[word_index] = query_word_index;
364 query_word, item, word_match_map))
367 bool all_main_group_matches = match->count_main_group_matches(item) ==
368 match->matched_word_indices.
size();
369 total_match_score += all_main_group_matches ? 4 : 3;
370 for (
const int i : match->matched_word_indices) {
371 word_match_map[i] = query_word_index;
381 if (word_index >= 0) {
382 total_match_score += 3 - error_count;
383 word_match_map[word_index] = query_word_index;
395 for (
const int index : word_match_map) {
397 match_indices.
append(index);
402 if (match_indices[i] > match_indices[i + 1]) {
403 total_match_score -= 1;
409 return total_match_score;
429 auto is_separator = [&](
uint32_t unicode) {
435 unicode_right_triangle);
442 char *mutable_copy =
const_cast<char *
>(str_copy.
data());
443 const size_t str_size_in_bytes = size_t(
str.size());
448 bool is_in_word =
false;
449 size_t word_start = 0;
451 while (offset < str_size_in_bytes) {
452 size_t size = offset;
455 if (is_separator(unicode)) {
457 const StringRef word = str_copy.
substr(
int(word_start),
int(offset - word_start));
459 r_word_group_ids.
append(group_id);
469 if (unicode == unicode_right_triangle) {
478 r_word_group_ids.
append(group_id);
490 int main_group_id = 0;
498 main_group_id = word_group_ids.
last();
503 word_group_ids.
fill(0);
509 int main_group_length = 0;
511 if (word_group_ids[i] == main_group_id) {
512 main_group_length +=
int(words[i].
size());
541 for (const int i : range) {
542 const SearchItem &item = items_[i];
543 const std::optional<float> score = string_search::score_query_against_words(query_words,
545 all_scores[i] = score;
549 for (
const int i : items_.index_range()) {
550 const std::optional<float> score = all_scores[i];
551 if (score.has_value()) {
552 result_indices_by_score.
add(*score, i);
556 Vector<float> found_scores;
557 for (
const float score : result_indices_by_score.keys()) {
558 found_scores.append(score);
560 std::sort(found_scores.begin(), found_scores.end(), std::greater<>());
564 Vector<int> sorted_result_indices;
565 for (
const float score : found_scores) {
566 MutableSpan<int> indices = result_indices_by_score.lookup(score);
567 if (score == found_scores[0]) {
568 if (!query.is_empty()) {
572 std::sort(indices.begin(), indices.end(), [&](
int a,
int b) {
573 const SearchItem &item_a = items_[a];
574 const SearchItem &item_b = items_[b];
576 return item_a.main_group_length < item_b.main_group_length ||
577 (item_a.main_group_length == item_b.main_group_length &&
578 item_a.total_length < item_b.total_length);
582 std::stable_sort(indices.begin(), indices.end(), [&](
int a,
int b) {
583 return items_[a].weight > items_[b].weight;
588 if (query.size() <= 1) {
590 std::stable_sort(indices.begin(), indices.end(), [&](
int a,
int b) {
591 return items_[a].recent_time > items_[b].recent_time;
595 sorted_result_indices.extend(indices);
598 Vector<void *> sorted_data(sorted_result_indices.size());
599 for (
const int i : sorted_result_indices.index_range()) {
600 const int result_index = sorted_result_indices[i];
601 const SearchItem &item = items_[result_index];
602 sorted_data[i] = item.user_data;
void BLI_str_tolower_ascii(char *str, size_t len) ATTR_NONNULL(1)
size_t size_t BLI_strnlen_utf8(const char *strc, size_t strc_maxlen) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
unsigned int BLI_str_utf8_as_unicode_step_safe(const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
unsigned int BLI_str_utf8_as_unicode_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
StringRefNull copy_string(StringRef str)
MutableSpan< T > construct_array_copy(Span< T > src)
Value lookup_default(const Key &key, const Value &default_value) const
void add(const Key &key, const Value &value)
constexpr T & last(const int64_t n=0) const
constexpr Span drop_front(int64_t n) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
static constexpr int64_t not_found
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr bool startswith(StringRef prefix) const
constexpr int64_t size() const
constexpr const char * data() const
constexpr StringRef drop_prefix(int64_t n) const
void append(const T &value)
const T & last(const int64_t n=0) const
IndexRange index_range() const
void fill(const T &value) const
Span< T > as_span() const
LinearAllocator allocator_
const RecentCache * recent_cache_
void add_impl(StringRef str, void *user_data, float weight)
Vector< SearchItem > items_
MainWordsHeuristic main_words_heuristic_
Vector< void * > query_impl(StringRef query) const
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static int64_t count_utf8_code_points(StringRef str)
static constexpr int unused_word
int get_fuzzy_match_errors(StringRef query, StringRef full)
static std::optional< InitialsMatch > match_word_initials(StringRef query, const SearchItem &item, const Span< int > word_match_map, int start=0)
static int get_best_word_index_that_startswith(StringRef query, const SearchItem &item, Span< int > word_match_map, Span< StringRef > remaining_query_words)
int damerau_levenshtein_distance(StringRef a, StringRef b)
static std::optional< float > score_query_against_words(Span< StringRef > query_words, const SearchItem &item)
static int get_word_index_that_fuzzy_matches(StringRef query, Span< StringRef > words, Span< int > word_match_map, int *r_error_count)
void extract_normalized_words(StringRef str, LinearAllocator<> &allocator, Vector< StringRef, 64 > &r_words, Vector< int, 64 > &r_word_group_ids)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
float distance(float a, float b)
#define UI_MENU_ARROW_SEP
#define UI_MENU_ARROW_SEP_UNICODE
int count_main_group_matches(const SearchItem &item) const
bool better_than(const InitialsMatch &other, const SearchItem &item) const
Vector< int > matched_word_indices
Map< std::string, int > logical_time_by_str
Span< StringRef > normalized_words
Span< int > word_group_ids