/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) */ #include "aa_tree.h" #include #ifdef UNDER_CE /* Windows CE: uintptr_t has already been defined by windows.h */ #elif !defined(_MSC_VER) || _MSC_VER >= 1800 # include #elif !defined(uintptr_t) /* Workaround missing standard includes in older Visual Studio */ # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 typedef _W64 unsigned int uintptr_t; # else typedef unsigned __int64 uintptr_t; # endif #endif #define aa_entry_container(head, entry) \ ((void*)((uintptr_t)entry - head->entry_offset)) #define aa_entry_key(head, entry) \ ((const void*)((uintptr_t)entry + head->key_offset - head->entry_offset)) #define aa_container_entry(head, container) \ ((struct aa_entry*)((uintptr_t)container + head->entry_offset)) #define aa_container_key(head, container) \ ((const void*)((uintptr_t)container + head->key_offset)) void aa_init(struct aa_head *head, enum aa_cmp (*cmp)(const void*, const void*), unsigned int entry_offset, unsigned int key_offset) { head->root = NULL; head->cmp = cmp; head->entry_offset = entry_offset; head->key_offset = key_offset; } static struct aa_entry * _aa_skew(struct aa_entry *n) { if(!n) return NULL; if(n->left && n->level == n->left->level) { struct aa_entry *l = n->left; n->left = l->right; l->right = n; return l; } return n; } static struct aa_entry * _aa_split(struct aa_entry *n) { if(!n) return NULL; if(n->right && n->right->right && n->right->right->level == n->level) { struct aa_entry *r = n->right; n->right = r->left; r->left = n; r->level++; return r; } return n; } static struct aa_entry * _aa_fixup(struct aa_entry *n) { unsigned int should_be = 0; if(n->left) should_be = n->left->level; if(n->right && n->right->level < should_be) should_be = n->right->level; should_be++; if(should_be < n->level) n->level = should_be; if(n->right && n->right->level > should_be) n->right->level = should_be; n = _aa_skew(n); n->right = _aa_skew(n->right); if(n->right) n->right->right = _aa_skew(n->right->right); n = _aa_split(n); n->right = _aa_split(n->right); return n; } static struct aa_entry * _aa_insert(struct aa_head *h, struct aa_entry *n, void *elem) { if(!n) { struct aa_entry *e = aa_container_entry(h, elem); e->left = NULL; e->right = NULL; e->level = 1; return e; } const void *n_key = aa_entry_key(h, n); const void *key = aa_container_key(h, elem); enum aa_cmp eq = h->cmp(key, n_key); if(eq == AA_CMP_EQ) eq = (key > n_key) ? AA_CMP_MORE : AA_CMP_LESS; if(eq == AA_CMP_LESS) n->left = _aa_insert(h, n->left, elem); else n->right = _aa_insert(h, n->right, elem); return _aa_split(_aa_skew(n)); } void aa_insert(struct aa_head *h, void *elem) { h->root = _aa_insert(h, h->root, elem); } void * aa_find(const struct aa_head *h, const void *key) { struct aa_entry *n = h->root; while(n) { enum aa_cmp eq = h->cmp(key, aa_entry_key(h, n)); if(eq == AA_CMP_EQ) return aa_entry_container(h, n); n = (eq == AA_CMP_LESS) ? n->left : n->right; } return NULL; } static struct aa_entry * unlink_succ(struct aa_entry *n, struct aa_entry **succ) { if(!n->left) { *succ = n; return n->right; } n->left = unlink_succ(n->left, succ); return _aa_fixup(n); } static struct aa_entry * unlink_pred(struct aa_entry *n, struct aa_entry **pred) { if(!n->right) { *pred = n; return n->left; } n->right = unlink_pred(n->right, pred); return _aa_fixup(n); } static struct aa_entry * _aa_remove(struct aa_head *h, void *elem, struct aa_entry *n) { if(!n) return NULL; const void *elem_key = aa_container_key(h, elem); const void *n_key = aa_entry_key(h, n); if(n_key == elem_key) { if(!n->left && !n->right) return NULL; struct aa_entry *replace = NULL; if(!n->left) n->right = unlink_succ(n->right, &replace); else n->left = unlink_pred(n->left, &replace); replace->left = n->left; replace->right = n->right; replace->level = n->level; return _aa_fixup(replace); } enum aa_cmp eq = h->cmp(elem_key, n_key); if(eq == AA_CMP_EQ) eq = (elem_key > n_key) ? AA_CMP_MORE : AA_CMP_LESS; if(eq == AA_CMP_LESS) n->left = _aa_remove(h, elem, n->left); else n->right = _aa_remove(h, elem, n->right); return _aa_fixup(n); } void aa_remove(struct aa_head *head, void *elem) { head->root = _aa_remove(head, elem, head->root); } void * aa_min(const struct aa_head *head) { struct aa_entry *e = head->root; if(!e) return NULL; while(e->left) e = e->left; return aa_entry_container(head, e); } void * aa_max(const struct aa_head *head) { struct aa_entry *e = head->root; if(!e) return NULL; while(e->right) e = e->right; return aa_entry_container(head, e); } void * aa_next(const struct aa_head *head, const void *elem) { struct aa_entry *e = aa_container_entry(head, elem); if(e->right) { e = e->right; while(e->left) e = e->left; return aa_entry_container(head, e); } struct aa_entry *next = NULL; struct aa_entry *n = head->root; const void *key = aa_container_key(head, elem); while(n && n != e) { const void *n_key = aa_entry_key(head, n); enum aa_cmp eq = head->cmp(key, n_key); if(eq == AA_CMP_EQ) eq = (key > n_key) ? AA_CMP_MORE : AA_CMP_LESS; if(eq == AA_CMP_MORE) { n = n->right; } else { next = n; n = n->left; } } return (next) ? aa_entry_container(head, next) : NULL; } void * aa_prev(const struct aa_head *head, const void *elem) { struct aa_entry *e = aa_container_entry(head, elem); if(e->left) { e = e->left; while(e->right) e = e->right; return aa_entry_container(head, e); } struct aa_entry *prev = NULL; struct aa_entry *n = head->root; const void *key = aa_container_key(head, elem); while(n && n != e) { const void *n_key = aa_entry_key(head, n); enum aa_cmp eq = head->cmp(key, n_key); if(eq == AA_CMP_EQ) eq = (key > n_key) ? AA_CMP_MORE : AA_CMP_LESS; if(eq == AA_CMP_MORE) { prev = n; n = n->right; } else { n = n->left; } } return (prev) ? aa_entry_container(head, prev) : NULL; }