mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
util/addon: use AVL trees
This commit is contained in:
parent
f83b3809cf
commit
27cbc20355
2 changed files with 255 additions and 19 deletions
|
|
@ -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);
|
||||
|
|
|
|||
261
util/addon.c
261
util/addon.c
|
|
@ -1,18 +1,119 @@
|
|||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/util/addon.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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -20,26 +121,158 @@ void wlr_addon_init(struct wlr_addon *addon, struct wlr_addon_set *set,
|
|||
const void *owner, const struct wlr_addon_interface *impl) {
|
||||
assert(owner && 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue