Skip to content

Commit

Permalink
New implementation without explicit direction
Browse files Browse the repository at this point in the history
  • Loading branch information
wismill committed Sep 17, 2023
1 parent cb7cf34 commit d0b3c18
Showing 1 changed file with 132 additions and 1 deletion.
133 changes: 132 additions & 1 deletion src/compose/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,9 @@ xkb_compose_table_entry_utf8(struct xkb_compose_table_entry *entry)
return entry->utf8;
}

#define ITER_IMPL 1
#define ITER_IMPL 3

#if ITER_IMPL == 1 || ITER_IMPL == 2

enum node_direction {
NODE_LEFT = 0,
Expand All @@ -263,17 +265,48 @@ struct xkb_compose_table_iterator_cursor {
* traversing the tree */
};

#elif ITER_IMPL == 3

struct xkb_compose_table_iterator_pending_node {
// [FIXME] faster to do __not__ use bit fields??
// uint32_t offset:31; /* WARNING: ensure it fits MAX_COMPOSE_NODES */
// bool processed:1;
uint32_t offset; /* WARNING: ensure it fits MAX_COMPOSE_NODES */
bool processed;
};

// [TODO] move to darray.h
#define darray_increase1(arr) do { \
(arr).size++; \
if ((arr).size > (arr).alloc) \
darray_realloc(arr, darray_next_alloc((arr).alloc, (arr).size, \
sizeof(*(arr).item))); \
} while (0)

#endif

struct xkb_compose_table_iterator {
struct xkb_compose_table *table;
/* Current entry */
struct xkb_compose_table_entry entry;
#if ITER_IMPL == 1 || ITER_IMPL == 2
darray(struct xkb_compose_table_iterator_cursor) cursors;
#else
/* Stack of pending nodes to process */
darray(struct xkb_compose_table_iterator_pending_node) nodes;
#endif
};

XKB_EXPORT struct xkb_compose_table_iterator *
xkb_compose_table_iterator_new(struct xkb_compose_table *table)
{
struct xkb_compose_table_iterator *iter;
#if ITER_IMPL == 1 || ITER_IMPL == 2
struct xkb_compose_table_iterator_cursor cursor;
#elif ITER_IMPL == 3
struct xkb_compose_table_iterator_pending_node *pending;
const struct compose_node *node;
#endif
xkb_keysym_t *sequence;

iter = calloc(1, sizeof(*iter));
Expand All @@ -289,20 +322,51 @@ xkb_compose_table_iterator_new(struct xkb_compose_table *table)
iter->entry.sequence = sequence;
iter->entry.sequence_length = 0;

#if ITER_IMPL == 1 || ITER_IMPL == 2

darray_init(iter->cursors);
cursor.direction = NODE_LEFT;
/* Offset 0 is a dummy null entry, skip it. */
cursor.node_offset = 1;
darray_append(iter->cursors, cursor);

#elif ITER_IMPL == 3

darray_init(iter->nodes);
/* Check if table contains only the dummy entry */
if (darray_size(table->nodes) == 1) {
return iter;
}
/* Add root node */
darray_resize(iter->nodes, 1);
pending = &darray_item(iter->nodes, 0);
pending->offset = 1;
pending->processed = false;
node = &darray_item(iter->table->nodes, pending->offset);

/* Find the first left-most node and store intermediate nodes as pending */
while (node->lokid) {
darray_increase1(iter->nodes);
pending = &darray_item(iter->nodes, darray_size(iter->nodes) - 1);
pending->offset = node->lokid;
pending->processed = false;
node = &darray_item(iter->table->nodes, pending->offset);
};

#endif

return iter;
}

XKB_EXPORT void
xkb_compose_table_iterator_free(struct xkb_compose_table_iterator *iter)
{
xkb_compose_table_unref(iter->table);
#if ITER_IMPL == 1 || ITER_IMPL == 2
darray_free(iter->cursors);
#else
darray_free(iter->nodes);
#endif
free(iter->entry.sequence);
free(iter);
}
Expand Down Expand Up @@ -375,7 +439,9 @@ xkb_compose_table_iterator_next(struct xkb_compose_table_iterator *iter)
}

return NULL;

#elif ITER_IMPL == 2

/*
* This function takes the following recursive traversal function,
* and makes it non-recursive and resumable. The iter->cursors stack
Expand Down Expand Up @@ -447,5 +513,70 @@ xkb_compose_table_iterator_next(struct xkb_compose_table_iterator *iter)
}

return NULL;

#elif ITER_IMPL == 3

struct xkb_compose_table_iterator_pending_node *pending;
const struct compose_node *node;

if (darray_empty(iter->nodes)) {
return NULL;
}

/* Resume to last element in the stack */
pending = &darray_item(iter->nodes, darray_size(iter->nodes) - 1);
node = &darray_item(iter->table->nodes, pending->offset);

/* Remove processed leaves and update entry accordingly */
while (pending->processed) {
/* Remove last keysym */
iter->entry.sequence_length--;
if (node->hikid) {
/* Follow right arrow: replace current pending node */
pending->processed = false;
pending->offset = node->hikid;
goto node_left;
} else {
/* Remove processed node */
darray_remove_last(iter->nodes);
if (darray_empty(iter->nodes)) {
/* No more nodes to process */
return NULL;
}
/* Get parent node */
pending = &darray_item(iter->nodes, darray_size(iter->nodes) - 1);
node = &darray_item(iter->table->nodes, pending->offset);
}
}

while (1) {
/* Follow down arrow */
pending->processed = true;
iter->entry.sequence[iter->entry.sequence_length] = node->keysym;
iter->entry.sequence_length++;
if (node->is_leaf) {
/* Leaf: return entry */
iter->entry.keysym = node->leaf.keysym;
iter->entry.utf8 = &darray_item(iter->table->utf8, node->leaf.utf8);
return &iter->entry;
}
/* Not a leaf: process child node */
darray_increase1(iter->nodes);
pending = &darray_item(iter->nodes, darray_size(iter->nodes) - 1);
pending->offset = node->internal.eqkid;
pending->processed = false;
node_left:
node = &darray_item(iter->table->nodes, pending->offset);
/* Find the next left-most arrow */
while (node->lokid) {
/* Follow left arrow */
darray_increase1(iter->nodes);
pending = &darray_item(iter->nodes, darray_size(iter->nodes) - 1);
pending->offset = node->lokid;
pending->processed = false;
node = &darray_item(iter->table->nodes, pending->offset);
}
}

#endif
}

0 comments on commit d0b3c18

Please sign in to comment.