コード例 #1
0
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;
}
コード例 #2
0
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;
}