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(' {{ 0x{value:08x}, {offs} }}, /* {name} */'.format(offs=entry_offsets[name], value=value, name=name))
|
||||||
|
|
||||||
print('static const struct name_keysym name_to_keysym[] = {')
|
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_entries(sorted(entries, key=lambda e: e[0].lower()))
|
||||||
print('};\n')
|
print('};\n')
|
||||||
|
|
||||||
|
|
113
src/keysym.c
113
src/keysym.c
|
@ -102,64 +102,75 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
|
||||||
if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
|
if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
|
||||||
return XKB_KEY_NoSymbol;
|
return XKB_KEY_NoSymbol;
|
||||||
|
|
||||||
size_t lo = 0, hi = ARRAY_SIZE(name_to_keysym) - 1;
|
/*
|
||||||
while (hi >= lo) {
|
* We need to !icase case to be fast, for e.g. Compose file parsing.
|
||||||
size_t mid = (lo + hi) / 2;
|
* So do it in a fast path.
|
||||||
int cmp = istrcmp(name, get_name(&name_to_keysym[mid]));
|
*/
|
||||||
if (cmp > 0) {
|
if (!icase) {
|
||||||
lo = mid + 1;
|
size_t lo = 0, hi = ARRAY_SIZE(name_to_keysym) - 1;
|
||||||
} else if (cmp < 0) {
|
while (hi >= lo) {
|
||||||
hi = mid - 1;
|
size_t mid = (lo + hi) / 2;
|
||||||
} else {
|
int cmp = strcmp(name, get_name(&name_to_keysym[mid]));
|
||||||
entry = &name_to_keysym[mid];
|
if (cmp > 0)
|
||||||
break;
|
lo = mid + 1;
|
||||||
|
else if (cmp < 0)
|
||||||
|
hi = mid - 1;
|
||||||
|
else
|
||||||
|
return name_to_keysym[mid].keysym;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entry) {
|
/*
|
||||||
/*
|
* Find the correct keysym for case-insensitive match.
|
||||||
* Find the correct keysym if one case-insensitive match is given.
|
*
|
||||||
*
|
* The name_to_keysym_icase table is sorted by istrcmp(). So the binary
|
||||||
* The name_to_keysym table is sorted by istrcmp(). So the binary search
|
* search may return _any_ of all possible case-insensitive duplicates. This
|
||||||
* may return _any_ of all possible case-insensitive duplicates. This
|
* code searches the entry, all previous and all next entries that match by
|
||||||
* code searches the entry, all previous and all next entries that match
|
* case-insensitive comparison and returns the "best" case-insensitive
|
||||||
* by case-insensitive comparison and returns the exact match to name.
|
* match.
|
||||||
* 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
|
||||||
* The "best" case-insensitive match is the lower-case keysym which we
|
* with the help of xkb_keysym_is_lower(). The only keysyms that only differ
|
||||||
* find with the help of xkb_keysym_is_lower().
|
* by letter-case are keysyms that are available as lower-case and
|
||||||
* The only keysyms that only differ by letter-case are keysyms that are
|
* upper-case variant (like KEY_a and KEY_A). So returning the first
|
||||||
* available as lower-case and upper-case variant (like KEY_a and
|
* lower-case match is enough in this case.
|
||||||
* 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;
|
||||||
const struct name_keysym *iter, *last;
|
while (hi >= lo) {
|
||||||
|
size_t mid = (lo + hi) / 2;
|
||||||
if (!icase && strcmp(get_name(entry), name) == 0)
|
int cmp = istrcmp(name, get_name(&name_to_keysym_icase[mid]));
|
||||||
return entry->keysym;
|
if (cmp > 0) {
|
||||||
if (icase && xkb_keysym_is_lower(entry->keysym))
|
lo = mid + 1;
|
||||||
return entry->keysym;
|
} else if (cmp < 0) {
|
||||||
|
hi = mid - 1;
|
||||||
for (iter = entry - 1; iter >= name_to_keysym; --iter) {
|
} else {
|
||||||
if (!icase && strcmp(get_name(iter), name) == 0)
|
entry = &name_to_keysym_icase[mid];
|
||||||
return iter->keysym;
|
|
||||||
if (istrcmp(get_name(iter), get_name(entry)) != 0)
|
|
||||||
break;
|
break;
|
||||||
if (icase && xkb_keysym_is_lower(iter->keysym))
|
}
|
||||||
return iter->keysym;
|
|
||||||
}
|
}
|
||||||
|
if (entry) {
|
||||||
|
const struct name_keysym *iter, *last;
|
||||||
|
|
||||||
last = name_to_keysym + ARRAY_SIZE(name_to_keysym);
|
if (icase && xkb_keysym_is_lower(entry->keysym))
|
||||||
for (iter = entry + 1; iter < last; ++iter) {
|
return entry->keysym;
|
||||||
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)
|
if (istrcmp(get_name(iter), get_name(entry)) != 0)
|
||||||
break;
|
break;
|
||||||
if (icase && xkb_keysym_is_lower(iter->keysym))
|
if (xkb_keysym_is_lower(iter->keysym))
|
||||||
return iter->keysym;
|
return iter->keysym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last = name_to_keysym_icase + ARRAY_SIZE(name_to_keysym_icase);
|
||||||
|
for (iter = entry + 1; iter < last; ++iter) {
|
||||||
|
if (istrcmp(get_name(iter), get_name(entry)) != 0)
|
||||||
|
break;
|
||||||
|
if (xkb_keysym_is_lower(iter->keysym))
|
||||||
|
return iter->keysym;
|
||||||
|
}
|
||||||
|
|
||||||
if (icase)
|
|
||||||
return entry->keysym;
|
return entry->keysym;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*name == 'U' || (icase && *name == 'u')) {
|
if (*name == 'U' || (icase && *name == 'u')) {
|
||||||
|
|
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