keysym: fast path for case sensitive xkb_keysym_from_name
xkb_keysym_from_name() is called a lot in Compose file parsing. The lower case handling slows things down a lot (particularly given we can't use the optimized strcasecmp() due to locale issues). So add separate handling for the non-case-sensitive case which is used by Compose. To do this we need to add another version of the ks_tables table. This adds ~20kb to the shared library binary. We can probably do something better here but I think it's fine. Signed-off-by: Ran Benita <ran@unusedvar.com>master
parent
3b506497bf
commit
7d84809fdc
|
@ -46,6 +46,10 @@ def print_entries(x):
|
|||
print(' {{ 0x{value:08x}, {offs} }}, /* {name} */'.format(offs=entry_offsets[name], value=value, name=name))
|
||||
|
||||
print('static const struct name_keysym name_to_keysym[] = {')
|
||||
print_entries(sorted(entries, key=lambda e: e[0]))
|
||||
print('};\n')
|
||||
|
||||
print('static const struct name_keysym name_to_keysym_icase[] = {')
|
||||
print_entries(sorted(entries, key=lambda e: e[0].lower()))
|
||||
print('};\n')
|
||||
|
||||
|
|
69
src/keysym.c
69
src/keysym.c
|
@ -102,65 +102,76 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
|
|||
if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
|
||||
return XKB_KEY_NoSymbol;
|
||||
|
||||
/*
|
||||
* We need to !icase case to be fast, for e.g. Compose file parsing.
|
||||
* So do it in a fast path.
|
||||
*/
|
||||
if (!icase) {
|
||||
size_t lo = 0, hi = ARRAY_SIZE(name_to_keysym) - 1;
|
||||
while (hi >= lo) {
|
||||
size_t mid = (lo + hi) / 2;
|
||||
int cmp = istrcmp(name, get_name(&name_to_keysym[mid]));
|
||||
int cmp = strcmp(name, get_name(&name_to_keysym[mid]));
|
||||
if (cmp > 0)
|
||||
lo = mid + 1;
|
||||
else if (cmp < 0)
|
||||
hi = mid - 1;
|
||||
else
|
||||
return name_to_keysym[mid].keysym;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Find the correct keysym for case-insensitive match.
|
||||
*
|
||||
* The name_to_keysym_icase table is sorted by istrcmp(). So the binary
|
||||
* search may return _any_ of all possible case-insensitive duplicates. This
|
||||
* code searches the entry, all previous and all next entries that match by
|
||||
* case-insensitive comparison and returns the "best" case-insensitive
|
||||
* match.
|
||||
*
|
||||
* The "best" case-insensitive match is the lower-case keysym which we find
|
||||
* with the help of xkb_keysym_is_lower(). The only keysyms that only differ
|
||||
* by letter-case are keysyms that are available as lower-case and
|
||||
* upper-case variant (like KEY_a and KEY_A). So returning the first
|
||||
* lower-case match is enough in this case.
|
||||
*/
|
||||
else {
|
||||
size_t lo = 0, hi = ARRAY_SIZE(name_to_keysym_icase) - 1;
|
||||
while (hi >= lo) {
|
||||
size_t mid = (lo + hi) / 2;
|
||||
int cmp = istrcmp(name, get_name(&name_to_keysym_icase[mid]));
|
||||
if (cmp > 0) {
|
||||
lo = mid + 1;
|
||||
} else if (cmp < 0) {
|
||||
hi = mid - 1;
|
||||
} else {
|
||||
entry = &name_to_keysym[mid];
|
||||
entry = &name_to_keysym_icase[mid];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (entry) {
|
||||
/*
|
||||
* Find the correct keysym if one case-insensitive match is given.
|
||||
*
|
||||
* The name_to_keysym table is sorted by istrcmp(). So the binary search
|
||||
* may return _any_ of all possible case-insensitive duplicates. This
|
||||
* code searches the entry, all previous and all next entries that match
|
||||
* by case-insensitive comparison and returns the exact match to name.
|
||||
* If icase is true, then this returns the best case-insensitive match
|
||||
* instead of a correct match.
|
||||
* The "best" case-insensitive match is the lower-case keysym which we
|
||||
* find with the help of xkb_keysym_is_lower().
|
||||
* The only keysyms that only differ by letter-case are keysyms that are
|
||||
* available as lower-case and upper-case variant (like KEY_a and
|
||||
* KEY_A). So returning the first lower-case match is enough in this
|
||||
* case.
|
||||
*/
|
||||
const struct name_keysym *iter, *last;
|
||||
|
||||
if (!icase && strcmp(get_name(entry), name) == 0)
|
||||
return entry->keysym;
|
||||
if (icase && xkb_keysym_is_lower(entry->keysym))
|
||||
return entry->keysym;
|
||||
|
||||
for (iter = entry - 1; iter >= name_to_keysym; --iter) {
|
||||
if (!icase && strcmp(get_name(iter), name) == 0)
|
||||
return iter->keysym;
|
||||
for (iter = entry - 1; iter >= name_to_keysym_icase; --iter) {
|
||||
if (istrcmp(get_name(iter), get_name(entry)) != 0)
|
||||
break;
|
||||
if (icase && xkb_keysym_is_lower(iter->keysym))
|
||||
if (xkb_keysym_is_lower(iter->keysym))
|
||||
return iter->keysym;
|
||||
}
|
||||
|
||||
last = name_to_keysym + ARRAY_SIZE(name_to_keysym);
|
||||
last = name_to_keysym_icase + ARRAY_SIZE(name_to_keysym_icase);
|
||||
for (iter = entry + 1; iter < last; ++iter) {
|
||||
if (!icase && strcmp(get_name(iter), name) == 0)
|
||||
return iter->keysym;
|
||||
if (istrcmp(get_name(iter), get_name(entry)) != 0)
|
||||
break;
|
||||
if (icase && xkb_keysym_is_lower(iter->keysym))
|
||||
if (xkb_keysym_is_lower(iter->keysym))
|
||||
return iter->keysym;
|
||||
}
|
||||
|
||||
if (icase)
|
||||
return entry->keysym;
|
||||
}
|
||||
}
|
||||
|
||||
if (*name == 'U' || (icase && *name == 'u')) {
|
||||
val = strtoul(&name[1], &tmp, 16);
|
||||
|
|
2554
src/ks_tables.h
2554
src/ks_tables.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue