Merge branch 'addon-tree' into 'master'

Draft: util/addon: use AVL trees

See merge request wlroots/wlroots!3806
This commit is contained in:
Kirill Primak 2023-07-06 12:55:22 +00:00
commit c8f0d27967
2 changed files with 255 additions and 19 deletions

View file

@ -9,26 +9,29 @@
#ifndef WLR_UTIL_ADDON_H
#define WLR_UTIL_ADDON_H
#include <wayland-server-core.h>
#include <stdint.h>
struct wlr_addon_set {
// private state
struct wl_list addons;
struct wlr_addon *root;
};
struct wlr_addon;
struct wlr_addon_interface {
const char *name;
// Has to call wlr_addon_finish()
void (*destroy)(struct wlr_addon *addon);
};
struct wlr_addon {
const struct wlr_addon_interface *impl;
// private state
struct wlr_addon_set *set;
const void *owner;
struct wl_list link;
const struct wlr_addon_interface *impl;
struct wlr_addon *parent; // NULL if it's set->root
struct wlr_addon *left;
struct wlr_addon *right;
int8_t balance;
};
void wlr_addon_set_init(struct wlr_addon_set *set);

View file

@ -1,19 +1,120 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/util/addon.h>
#include <wlr/util/log.h>
static ptrdiff_t compare(struct wlr_addon *addon, const void *owner,
const struct wlr_addon_interface *impl) {
ptrdiff_t owner_diff = (ptrdiff_t)addon->owner - (ptrdiff_t)owner;
if (owner_diff != 0) {
return owner_diff;
}
return (ptrdiff_t)addon->impl - (ptrdiff_t)impl;
}
// A (addon (child)) => A (child)
static void replace(struct wlr_addon *addon, struct wlr_addon *child) {
if (addon->parent == NULL) {
addon->set->root = child;
} else if (addon->parent->left == addon) {
addon->parent->left = child;
} else { // addon->parent->right == addon
addon->parent->right = child;
}
if (child != NULL) {
child->parent = addon->parent;
}
}
// parent (A, addon (B, C)) => addon (parent (A, B), C)
static struct wlr_addon *rotate_left(struct wlr_addon *parent,
struct wlr_addon *addon) {
parent->right = addon->left;
if (addon->left != NULL) {
addon->left->parent = parent;
}
addon->left = parent;
parent->parent = addon;
if (addon->balance == 0) {
addon->balance = -1;
parent->balance = 1;
} else {
addon->balance = 0;
parent->balance = 0;
}
return addon;
}
// parent (addon (A, B), C) => addon (A, parent (B, C))
static struct wlr_addon *rotate_right(struct wlr_addon *parent,
struct wlr_addon *addon) {
parent->left = addon->right;
if (addon->right != NULL) {
addon->right->parent = parent;
}
addon->right = parent;
parent->parent = addon;
if (addon->balance == 0) {
addon->balance = -1;
parent->balance = 1;
} else {
addon->balance = 0;
parent->balance = 0;
}
return addon;
}
// parent (addon (A, mid (B, C)), D) => mid (addon (A, B), parent (C, D))
static struct wlr_addon *rotate_leftright(struct wlr_addon *parent,
struct wlr_addon *addon) {
struct wlr_addon *mid = addon->right;
addon->right = mid->left;
if (mid->left != NULL) {
mid->left->parent = addon;
}
mid->left = addon;
addon->parent = mid;
parent->left = mid->right;
if (mid->right != NULL) {
mid->right->parent = parent;
}
mid->right = parent;
parent->parent = mid;
parent->balance = mid->balance > 0 ? -1 : 0;
addon->balance = mid->balance < 0 ? 1 : 0;
return mid;
}
// parent (A, addon (mid (B, C), D)) => mid (parent (A, B), addon (C, D))
static struct wlr_addon *rotate_rightleft(struct wlr_addon *parent,
struct wlr_addon *addon) {
struct wlr_addon *mid = addon->left;
addon->left = mid->right;
if (mid->right != NULL) {
mid->right->parent = addon;
}
mid->right = addon;
addon->parent = mid;
parent->right = mid->left;
if (mid->left != NULL) {
mid->left->parent = parent;
}
mid->left = parent;
parent->parent = mid;
parent->balance = mid->balance > 0 ? -1 : 0;
addon->balance = mid->balance < 0 ? 1 : 0;
return mid;
}
void wlr_addon_set_init(struct wlr_addon_set *set) {
memset(set, 0, sizeof(*set));
wl_list_init(&set->addons);
}
void wlr_addon_set_finish(struct wlr_addon_set *set) {
struct wlr_addon *addon, *tmp;
wl_list_for_each_safe(addon, tmp, &set->addons, link) {
addon->impl->destroy(addon);
while (set->root != NULL) {
set->root->impl->destroy(set->root);
}
wl_list_for_each(addon, &set->addons, link) {
@ -27,26 +128,158 @@ void wlr_addon_init(struct wlr_addon *addon, struct wlr_addon_set *set,
const void *owner, const struct wlr_addon_interface *impl) {
assert(impl);
memset(addon, 0, sizeof(*addon));
struct wlr_addon *iter;
wl_list_for_each(iter, &set->addons, link) {
if (iter->owner == addon->owner && iter->impl == addon->impl) {
assert(0 && "Can't have two addons of the same type with the same owner");
struct wlr_addon *parent = NULL;
struct wlr_addon **ptr = &set->root;
while (*ptr != NULL) {
parent = *ptr;
ptrdiff_t diff = compare(*ptr, owner, impl);
if (diff < 0) {
ptr = &(*ptr)->left;
} else if (diff > 0) {
ptr = &(*ptr)->right;
} else {
assert(0 && "Can't have two addons with the same owner and impl");
return;
}
}
wl_list_insert(&set->addons, &addon->link);
addon->set = set;
addon->owner = owner;
addon->impl = impl;
addon->parent = parent;
*ptr = addon;
// Rebalance
for (; parent != NULL; parent = parent->parent) {
struct wlr_addon *grandparent = parent->parent;
if (parent->left == addon) {
if (parent->balance > 0) {
parent->balance = 0;
break;
} else if (parent->balance == 0) {
parent->balance = -1;
addon = parent;
continue;
}
if (addon->balance > 0) {
addon = rotate_leftright(parent, addon);
} else {
addon = rotate_right(parent, addon);
}
} else { // parent->right == addon
if (parent->balance < 0) {
parent->balance = 0;
break;
} else if (parent->balance == 0) {
parent->balance = 1;
addon = parent;
continue;
}
if (addon->balance < 0) {
addon = rotate_rightleft(parent, addon);
} else {
addon = rotate_left(parent, addon);
}
}
// Here, addon is the root of the rotated subtree
addon->parent = grandparent;
if (grandparent != NULL) {
if (grandparent->left == parent) {
grandparent->left = addon;
} else { // grandparent->right == parent
grandparent->right = addon;
}
} else {
set->root = addon;
}
break;
}
}
void wlr_addon_finish(struct wlr_addon *addon) {
wl_list_remove(&addon->link);
if (addon->left == NULL) {
replace(addon, addon->right);
} else if (addon->right == NULL) {
replace(addon, addon->left);
} else {
struct wlr_addon *successor = addon->right;
while (successor->left != NULL) {
successor = successor->left;
}
if (successor->parent != addon) {
replace(successor, successor->right);
successor->right = addon->right;
successor->right->parent = successor;
}
replace(addon, successor);
successor->left = addon->left;
successor->left->parent = successor;
}
// Rebalance
for (struct wlr_addon *parent = addon->parent;
parent != NULL; parent = parent->parent) {
int balance = 0;
struct wlr_addon *grandparent = parent->parent;
if (parent->left == addon) {
if (parent->balance < 0) {
parent->balance = 0;
addon = parent;
continue;
} else if (parent->balance == 0) {
parent->balance = 1;
break;
}
balance = parent->right->balance;
if (balance < 0) {
addon = rotate_rightleft(parent, addon);
} else {
addon = rotate_left(parent, addon);
}
} else { // parent->right == addon
if (parent->balance < 0) {
parent->balance = 0;
addon = parent;
continue;
} else if (parent->balance == 0) {
parent->balance = -1;
break;
}
balance = parent->left->balance;
if (balance > 0) {
addon = rotate_leftright(parent, addon);
} else {
addon = rotate_right(parent, addon);
}
}
// Here, addon is the root of the rotated subtree
addon->parent = grandparent;
if (grandparent != NULL) {
if (grandparent->left == parent) {
grandparent->left = addon;
} else { // grandparent->right == parent
grandparent->right = addon;
}
} else {
addon->set->root = addon;
}
if (balance == 0) {
break;
}
}
}
struct wlr_addon *wlr_addon_find(struct wlr_addon_set *set, const void *owner,
const struct wlr_addon_interface *impl) {
struct wlr_addon *addon;
wl_list_for_each(addon, &set->addons, link) {
if (addon->owner == owner && addon->impl == impl) {
struct wlr_addon *addon = set->root;
while (addon != NULL) {
ptrdiff_t diff = compare(addon, owner, impl);
if (diff < 0) {
addon = addon->left;
} else if (diff > 0) {
addon = addon->right;
} else {
return addon;
}
}