Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add iterator API for Compose table #367

Merged
merged 1 commit into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions bench/compose-traversal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright © 2023 Pierre Le Marre
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

#include "config.h"

#include <time.h>

#include "xkbcommon/xkbcommon-compose.h"

#include "../test/test.h"
#include "bench.h"

#define BENCHMARK_ITERATIONS 1000

int
main(void)
{
struct xkb_context *ctx;
char *path;
FILE *file;
struct xkb_compose_table *table;
struct xkb_compose_table_iterator *iter;
struct xkb_compose_table_entry *entry;
struct bench bench;
char *elapsed;

ctx = test_get_context(CONTEXT_NO_FLAG);
assert(ctx);

path = test_get_path("locale/en_US.UTF-8/Compose");
file = fopen(path, "rb");
if (file == NULL) {
perror(path);
free(path);
xkb_context_unref(ctx);
return -1;
}
free(path);

xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
xkb_context_set_log_verbosity(ctx, 0);

table = xkb_compose_table_new_from_file(ctx, file, "",
XKB_COMPOSE_FORMAT_TEXT_V1,
XKB_COMPOSE_COMPILE_NO_FLAGS);
fclose(file);
assert(table);

bench_start(&bench);
for (int i = 0; i < BENCHMARK_ITERATIONS; i++) {
iter = xkb_compose_table_iterator_new(table);
while ((entry = xkb_compose_table_iterator_next(iter))) {
assert (entry);
}
xkb_compose_table_iterator_free(iter);
}
bench_stop(&bench);

xkb_compose_table_unref(table);

elapsed = bench_elapsed_str(&bench);
fprintf(stderr, "traversed %d compose tables in %ss\n",
BENCHMARK_ITERATIONS, elapsed);
free(elapsed);

xkb_context_unref(ctx);
return 0;
}
137 changes: 137 additions & 0 deletions include/xkbcommon/xkbcommon-compose.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,143 @@ xkb_compose_table_ref(struct xkb_compose_table *table);
void
xkb_compose_table_unref(struct xkb_compose_table *table);

/**
* @struct xkb_compose_table_entry
* Opaque Compose table entry object.
*
* Represents a single entry in a Compose file in the iteration API.
* It is immutable.
*
* @sa xkb_compose_table_iterator_new
* @since 1.6.0
*/
struct xkb_compose_table_entry;

/**
* Get the left-hand keysym sequence of a Compose table entry.
*
* For example, given the following entry:
*
* ```
* <dead_tilde> <space> : "~" asciitilde # TILDE
* ```
*
* it will return `{XKB_KEY_dead_tilde, XKB_KEY_space}`.
*
* @param[in] entry The compose table entry object to process.
*
* @param[out] sequence_length Number of keysyms in the sequence.
*
* @returns The array of left-hand side keysyms. The number of keysyms
* is returned in the @p sequence_length out-parameter.
*
* @memberof xkb_compose_table_entry
* @since 1.6.0
*/
const xkb_keysym_t *
xkb_compose_table_entry_sequence(struct xkb_compose_table_entry *entry,
size_t *sequence_length);

/**
* Get the right-hand result keysym of a Compose table entry.
*
* For example, given the following entry:
*
* ```
* <dead_tilde> <space> : "~" asciitilde # TILDE
* ```
*
* it will return `XKB_KEY_asciitilde`.
*
* The keysym is optional; if the entry does not specify a keysym,
* returns `XKB_KEY_NoSymbol`.
*
* @memberof xkb_compose_table_entry
* @since 1.6.0
*/
xkb_keysym_t
xkb_compose_table_entry_keysym(struct xkb_compose_table_entry *entry);

/**
* Get the right-hand result string of a Compose table entry.
*
* The string is UTF-8 encoded and NULL-terminated.
*
* For example, given the following entry:
*
* ```
* <dead_tilde> <space> : "~" asciitilde # TILDE
* ```
*
* it will return `"~"`.
*
* The string is optional; if the entry does not specify a string,
* returns the empty string.
*
* @memberof xkb_compose_table_entry
* @since 1.6.0
*/
const char *
xkb_compose_table_entry_utf8(struct xkb_compose_table_entry *entry);

/**
* @struct xkb_compose_table_iterator
* Iterator over a compose table’s entries.
*
* @sa xkb_compose_table_iterator_new()
* @since 1.6.0
*/
struct xkb_compose_table_iterator;

/**
* Create a new iterator for a compose table.
*
* Intended use:
*
* ```c
wismill marked this conversation as resolved.
Show resolved Hide resolved
* struct xkb_compose_table_iterator *iter = xkb_compose_table_iterator_new(compose_table);
* struct xkb_compose_table_entry *entry;
* while ((entry = xkb_compose_table_iterator_next(iter))) {
* // ...
* }
* xkb_compose_table_iterator_free(iter);
* ```
*
* @returns A new compose table iterator, or `NULL` on failure.
*
* @memberof xkb_compose_table_iterator
* @sa xkb_compose_table_iterator_free()
* @since 1.6.0
*/
struct xkb_compose_table_iterator *
xkb_compose_table_iterator_new(struct xkb_compose_table *table);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking that if we ever want to modify this, e.g. add support for preserving the original entries order, then we should add a flags argument to future proof it. BUT, I think that's unlikely enough that it's not worth it. We would just add a xkb_compose_table_iterator_new2 function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the use case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like support for preserving the original entries order. But as I said we can omit the flags now as it's probably not going to be needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I understand the preserving order part, but where would it be useful? One use case I see is for cleaning/normalizing compose files, but as we do not keep comments nor white spaces, such a hypothetical tool will still have to parse and compare resulting entries with xkbcommon.


/**
* Free a compose iterator.
*
* @memberof xkb_compose_table_iterator
* @since 1.6.0
*/
void
xkb_compose_table_iterator_free(struct xkb_compose_table_iterator *iter);

/**
* Get the next compose entry from a compose table iterator.
*
* The entries are returned in lexicographic order of the left-hand
* side of entries. This does not correspond to the order in which
* the entries appear in the Compose file.
*
* @attention The return value is valid until the next call to this function.
*
* Returns `NULL` in case there is no more entries.
wismill marked this conversation as resolved.
Show resolved Hide resolved
*
* @memberof xkb_compose_table_iterator
* @since 1.6.0
*/
struct xkb_compose_table_entry *
xkb_compose_table_iterator_next(struct xkb_compose_table_iterator *iter);

/** Flags for compose state creation. */
enum xkb_compose_state_flags {
/** Do not apply any flags. */
Expand Down
5 changes: 5 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,11 @@ benchmark(
executable('bench-compose', 'bench/compose.c', dependencies: test_dep),
env: bench_env,
)
benchmark(
'compose-traversal',
executable('bench-compose-traversal', 'bench/compose-traversal.c', dependencies: test_dep),
env: bench_env,
)
benchmark(
'atom',
executable('bench-atom', 'bench/atom.c', dependencies: test_dep),
Expand Down
3 changes: 0 additions & 3 deletions src/compose/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@ OR PERFORMANCE OF THIS SOFTWARE.
#include "utf8.h"
#include "parser.h"

#define MAX_LHS_LEN 10
#define MAX_INCLUDE_DEPTH 5

/*
* Grammar adapted from libX11/modules/im/ximcp/imLcPrs.c.
* See also the XCompose(5) manpage.
Expand Down
3 changes: 3 additions & 0 deletions src/compose/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#ifndef COMPOSE_PARSER_H
#define COMPOSE_PARSER_H

#define MAX_LHS_LEN 10
#define MAX_INCLUDE_DEPTH 5

bool
parse_string(struct xkb_compose_table *table,
const char *string, size_t len,
Expand Down
Loading