int py_enhance_stroke_get_match_keys(PinyinEnhance *pyenhance, const char *key_s, int key_l, const PyEnhanceMapWord **word_buff, int buff_len) { const PyEnhanceStrokeTree *tree; int i; int count = 0; char *key_buff = malloc(key_l + 1); for (i = 0;i < key_l;i++) { key_buff[i] = py_enhance_stroke_sym_to_num(key_s[i]); } key_buff[key_l] = '\0'; key_buff[0] -= '1'; tree = &pyenhance->stroke_tree; if (buff_len > 16) buff_len = 16; switch (key_l) { case 1: { const PyEnhanceMapWord *tmp_word; tmp_word = tree->singles[(int)key_buff[0]]; if (tmp_word) { word_buff[0] = tmp_word; count++; if (count >= buff_len) { goto out; } } PyEnhanceMapWord *const *tmp_word_p; tmp_word_p = tree->doubles[(int)key_buff[0]]; int left = buff_len - count; if (left > 5) left = 5; memcpy(word_buff + count, tmp_word_p, left * sizeof(PyEnhanceMapWord*)); count += left; goto out; } case 2: { const PyEnhanceMapWord *tmp_word; key_buff[1] -= '1'; tmp_word = tree->doubles[(int)key_buff[0]][(int)key_buff[1]]; if (tmp_word) { word_buff[0] = tmp_word; count++; if (count >= buff_len) { goto out; } } PyEnhanceStrokeKey *const *tmp_key_p; const PyEnhanceStrokeKey *tmp_key; tmp_key_p = tree->multiples[(int)key_buff[0]][(int)key_buff[1]]; for (i = 0;count < buff_len && i < 5;i++) { tmp_key = tmp_key_p[i]; if (!tmp_key || *py_enhance_stroke_get_key(tmp_key)) continue; word_buff[count] = tmp_key->words; count++; } goto out; } default: break; } // maximum size from (key_buff[0] == i || key_buff[1] == j) PyEnhanceStrokeKeyLookup lookup[(5 + 5 - 1) * 5]; const PyEnhanceStrokeKey *tmp_key; int lookup_c = 0; int j; int k; key_buff[1] -= '1'; key_buff[2] -= '1'; key_s = key_buff + 3; key_l -= 3; for (i = 0;i < 5;i++) { for (j = 0;j < 5;j++) { boolean diff0 = key_buff[0] != i; boolean diff1 = key_buff[1] != j; if (diff0 && diff1) continue; for (k = 0;k < 5;k++) { tmp_key = (tree->multiples[i][j][k]); if (!tmp_key) continue; PyEnhanceStrokeKeyLookup *lookup_p = lookup + lookup_c; if (key_buff[2] == k) { lookup_p->key = tmp_key; lookup_p->key_s = key_s; lookup_p->key_l = key_l; lookup_p->diff = diff0 + diff1; lookup_c++; continue; } if (diff0 || diff1) continue; lookup_p->key = tmp_key; lookup_p->key_s = key_s - 1; lookup_p->key_l = key_l + 1; lookup_p->diff = 1; lookup_c++; } } } key_buff[2] += '1'; int cur_len = key_l * 2 / 3; PyEnhanceStrokeResult res_buff[16]; while (lookup_c > 0 && (count < buff_len || cur_len <= key_l + 4)) { for (i = 0;i < lookup_c;i++) { PyEnhanceStrokeKeyLookup *lookup_p = lookup + i; if (!lookup_p->key) { lookup_c--; memmove(lookup_p, lookup_p + 1, sizeof(PyEnhanceStrokeKeyLookup) * (lookup_c - i)); i--; continue; } while (lookup_p->key && lookup_p->key->key_l < cur_len) { lookup_p->key = lookup_p->key->next; } for (;lookup_p->key && lookup_p->key->key_l == cur_len; lookup_p->key = lookup_p->key->next) { int distance = py_enhance_stroke_get_distance( lookup_p->key_s, lookup_p->key_l, py_enhance_stroke_get_key(lookup_p->key), lookup_p->key->key_l); if (distance < 0) continue; distance += lookup_p->diff * REPLACE_WEIGHT; for (j = 0;j < count;j++) { if (distance < res_buff[j].distance) { break; } } if (count < buff_len) { count++; } else if (j >= count) { continue; } PyEnhanceStrokeResult *pos = res_buff + j; int move_size = count - j - 1; if (move_size > 0) { memmove(pos + 1, pos, move_size * sizeof(PyEnhanceStrokeResult)); } pos->word = lookup_p->key->words; pos->distance = distance; } } cur_len++; } for (j = 0;j < count;j++) { word_buff[j] = res_buff[j].word; } out: free(key_buff); return count; }
int py_enhance_stroke_get_match_keys( PinyinEnhance *pyenhance, const char *key_s, int key_l, PyEnhanceStrokeWord **word_buff, int buff_len) { int i; int count = 0; uint8_t *key_buff = malloc(key_l); for (i = 0;i < key_l;i++) { key_buff[i] = py_enhance_stroke_sym_to_num(key_s[i]); if (fcitx_unlikely(key_buff[i] == (uint8_t)-1)) { goto out; } } const PyEnhanceStrokeTree *tree = &pyenhance->stroke_tree; if (buff_len > 16) buff_len = 16; switch (key_l) { case 1: { uint32_t tmp_word = *py_enhance_get_single(tree, key_buff[0]); if (tmp_word % 4 == 0) { word_buff[0] = _py_enhance_stroke_id_to_word(tree, tmp_word); count++; if (count >= buff_len) { goto out; } } const uint32_t *tmp_word_p = py_enhance_get_double(tree, key_buff[0]); int left = buff_len - count; if (left > 5) left = 5; for (i = 0;i < left;i++) { word_buff[count + i] = _py_enhance_stroke_id_to_word( tree, tmp_word_p[i]); } count += left; goto out; } case 2: { uint32_t tmp_word; tmp_word = *py_enhance_get_double(tree, key_buff[0], key_buff[1]); if (tmp_word % 4 == 0) { word_buff[0] = _py_enhance_stroke_id_to_word(tree, tmp_word); count++; if (count >= buff_len) { goto out; } } const uint32_t *tmp_key_p; const PyEnhanceStrokeKey *tmp_key; tmp_key_p = py_enhance_get_multiple(tree, key_buff[0], key_buff[1]); int left = buff_len - count; if (left > 5) left = 5; for (i = 0;i < left;i++) { tmp_key = py_enhance_stroke_id_to_key(tree, tmp_key_p[i]); /** * skip if there the prefix has no keys or the shortest key in the * series is longer than 3 (i.e. > 0 after the prefix is removed.) **/ if (!tmp_key || tmp_key->key_l) continue; word_buff[count] = py_enhance_stroke_id_to_word(tree, tmp_key->words); count++; } goto out; } default: break; } // maximum size from (key_buff[0] == i || key_buff[1] == j) PyEnhanceStrokeKeyLookup lookup[(5 + 5 - 1) * 5]; const PyEnhanceStrokeKey *tmp_key; uint32_t tmp_key_id; int lookup_c = 0; int j; int k; uint8_t *key_p; key_p = key_buff + 3; key_l -= 3; for (i = 0;i < 5;i++) { for (j = 0;j < 5;j++) { boolean diff0 = key_buff[0] != i; boolean diff1 = key_buff[1] != j; if (diff0 && diff1) continue; for (k = 0;k < 5;k++) { tmp_key_id = *py_enhance_get_multiple(tree, i, j, k); if (tmp_key_id % 4 != 0) continue; tmp_key = _py_enhance_stroke_id_to_key(tree, tmp_key_id); PyEnhanceStrokeKeyLookup *lookup_p = lookup + lookup_c; if (key_buff[2] == k) { lookup_p->key = tmp_key; lookup_p->key_s = key_p; lookup_p->key_l = key_l; lookup_p->diff = diff0 + diff1; lookup_c++; continue; } if (diff0 || diff1) continue; lookup_p->key = tmp_key; lookup_p->key_s = key_p - 1; lookup_p->key_l = key_l + 1; lookup_p->diff = 1; lookup_c++; } } } int cur_len = key_l * 2 / 3; PyEnhanceStrokeResult res_buff[16]; while (lookup_c > 0 && (count < buff_len || cur_len <= key_l + 4)) { /** * check keys of certain length for all prefix. **/ for (i = 0;i < lookup_c;i++) { PyEnhanceStrokeKeyLookup *lookup_p = lookup + i; /** * remove a prefix if it is already reached the end. **/ if (!lookup_p->key) { lookup_c--; memmove(lookup_p, lookup_p + 1, sizeof(PyEnhanceStrokeKeyLookup) * (lookup_c - i)); i--; continue; } /** * skip keys shorter than the current length. **/ while (lookup_p->key && lookup_p->key->key_l < cur_len) { py_enhance_stroke_key_tonext(tree, &lookup_p->key); } for (;lookup_p->key && lookup_p->key->key_l == cur_len; py_enhance_stroke_key_tonext(tree, &lookup_p->key)) { int distance = py_enhance_stroke_get_distance( lookup_p->key_s, lookup_p->key_l, lookup_p->key->key, lookup_p->key->key_l); if (distance < 0) continue; distance += lookup_p->diff * REPLACE_WEIGHT; /** * insert in the ordered result array. **/ for (j = 0;j < count;j++) { if (distance < res_buff[j].distance) { break; } } if (count < buff_len) { count++; } else if (j >= count) { continue; } PyEnhanceStrokeResult *pos = res_buff + j; int move_size = count - j - 1; if (move_size > 0) { memmove(pos + 1, pos, move_size * sizeof(PyEnhanceStrokeResult)); } pos->word = lookup_p->key->words; pos->distance = distance; } } cur_len++; } for (j = 0;j < count;j++) { word_buff[j] = py_enhance_stroke_id_to_word(tree, res_buff[j].word); } out: free(key_buff); return count; }