Rewrite WMBag in Rust.
We should eventually get rid of this entirely, in favor of something along the lines of a sorted Vec that is fully typed (so the payload isn't just a void*).
This commit is contained in:
@@ -65,7 +65,6 @@ libWINGs_la_SOURCES = \
|
||||
wwindow.c
|
||||
|
||||
libWUtil_la_SOURCES = \
|
||||
bagtree.c \
|
||||
error.c \
|
||||
error.h \
|
||||
findfile.c \
|
||||
|
||||
@@ -173,7 +173,7 @@ typedef struct {
|
||||
|
||||
|
||||
typedef int WMArrayIterator;
|
||||
typedef void *WMBagIterator;
|
||||
typedef int WMBagIterator;
|
||||
|
||||
|
||||
typedef void WMNotificationObserverAction(void *observerData,
|
||||
@@ -479,7 +479,7 @@ void* WMArrayPrevious(WMArray *array, WMArrayIterator *iter);
|
||||
for (var = WMArrayLast(array, &(i)); (i) != WANotFound; \
|
||||
var = WMArrayPrevious(array, &(i)))
|
||||
|
||||
/* ---[ WINGs/bagtree.c ]------------------------------------------------- */
|
||||
/* ---[ wutil-rs/src/bag.rs ]------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Tree bags use a red-black tree for storage.
|
||||
@@ -498,9 +498,7 @@ WMBag* WMCreateTreeBag(void);
|
||||
|
||||
void* WMGetFromBag(WMBag *bag, int index);
|
||||
|
||||
void* WMReplaceInBag(WMBag *bag, int index, void *item);
|
||||
|
||||
#define WMSetInBag(bag, index, item) WMReplaceInBag(bag, index, item)
|
||||
void WMSetInBag(WMBag *bag, int index, void *item);
|
||||
|
||||
void WMEmptyBag(WMBag *bag);
|
||||
|
||||
@@ -521,7 +519,7 @@ void* WMBagIteratorAtIndex(WMBag *bag, int index, WMBagIterator *ptr);
|
||||
/* The following macro assumes that the bag doesn't change in the for loop */
|
||||
|
||||
#define WM_ETARETI_BAG(bag, var, i) \
|
||||
for (var = WMBagLast(bag, &(i)); (i) != NULL; \
|
||||
for (var = WMBagLast(bag, &(i)); (i) >= 0; \
|
||||
var = WMBagPrevious(bag, &(i)))
|
||||
|
||||
|
||||
|
||||
531
WINGs/bagtree.c
531
WINGs/bagtree.c
@@ -1,531 +0,0 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "WUtil.h"
|
||||
|
||||
typedef struct W_Node {
|
||||
struct W_Node *parent;
|
||||
struct W_Node *left;
|
||||
struct W_Node *right;
|
||||
int color;
|
||||
|
||||
void *data;
|
||||
int index;
|
||||
} W_Node;
|
||||
|
||||
typedef struct W_Bag {
|
||||
W_Node *root;
|
||||
|
||||
W_Node *nil; /* sentinel */
|
||||
|
||||
int count;
|
||||
|
||||
} W_Bag;
|
||||
|
||||
#define IS_LEFT(node) (node == node->parent->left)
|
||||
#define IS_RIGHT(node) (node == node->parent->right)
|
||||
|
||||
static void leftRotate(W_Bag * tree, W_Node * node)
|
||||
{
|
||||
W_Node *node2;
|
||||
|
||||
node2 = node->right;
|
||||
node->right = node2->left;
|
||||
|
||||
node2->left->parent = node;
|
||||
|
||||
node2->parent = node->parent;
|
||||
|
||||
if (node->parent == tree->nil) {
|
||||
tree->root = node2;
|
||||
} else {
|
||||
if (IS_LEFT(node)) {
|
||||
node->parent->left = node2;
|
||||
} else {
|
||||
node->parent->right = node2;
|
||||
}
|
||||
}
|
||||
node2->left = node;
|
||||
node->parent = node2;
|
||||
}
|
||||
|
||||
static void rightRotate(W_Bag * tree, W_Node * node)
|
||||
{
|
||||
W_Node *node2;
|
||||
|
||||
node2 = node->left;
|
||||
node->left = node2->right;
|
||||
|
||||
node2->right->parent = node;
|
||||
|
||||
node2->parent = node->parent;
|
||||
|
||||
if (node->parent == tree->nil) {
|
||||
tree->root = node2;
|
||||
} else {
|
||||
if (IS_LEFT(node)) {
|
||||
node->parent->left = node2;
|
||||
} else {
|
||||
node->parent->right = node2;
|
||||
}
|
||||
}
|
||||
node2->right = node;
|
||||
node->parent = node2;
|
||||
}
|
||||
|
||||
static void treeInsert(W_Bag * tree, W_Node * node)
|
||||
{
|
||||
W_Node *y = tree->nil;
|
||||
W_Node *x = tree->root;
|
||||
|
||||
while (x != tree->nil) {
|
||||
y = x;
|
||||
if (node->index <= x->index)
|
||||
x = x->left;
|
||||
else
|
||||
x = x->right;
|
||||
}
|
||||
node->parent = y;
|
||||
if (y == tree->nil)
|
||||
tree->root = node;
|
||||
else if (node->index <= y->index)
|
||||
y->left = node;
|
||||
else
|
||||
y->right = node;
|
||||
}
|
||||
|
||||
static void rbTreeInsert(W_Bag * tree, W_Node * node)
|
||||
{
|
||||
W_Node *y;
|
||||
|
||||
treeInsert(tree, node);
|
||||
|
||||
node->color = 'R';
|
||||
|
||||
while (node != tree->root && node->parent->color == 'R') {
|
||||
if (IS_LEFT(node->parent)) {
|
||||
y = node->parent->parent->right;
|
||||
|
||||
if (y->color == 'R') {
|
||||
|
||||
node->parent->color = 'B';
|
||||
y->color = 'B';
|
||||
node->parent->parent->color = 'R';
|
||||
node = node->parent->parent;
|
||||
|
||||
} else {
|
||||
if (IS_RIGHT(node)) {
|
||||
node = node->parent;
|
||||
leftRotate(tree, node);
|
||||
}
|
||||
node->parent->color = 'B';
|
||||
node->parent->parent->color = 'R';
|
||||
rightRotate(tree, node->parent->parent);
|
||||
}
|
||||
} else {
|
||||
y = node->parent->parent->left;
|
||||
|
||||
if (y->color == 'R') {
|
||||
|
||||
node->parent->color = 'B';
|
||||
y->color = 'B';
|
||||
node->parent->parent->color = 'R';
|
||||
node = node->parent->parent;
|
||||
|
||||
} else {
|
||||
if (IS_LEFT(node)) {
|
||||
node = node->parent;
|
||||
rightRotate(tree, node);
|
||||
}
|
||||
node->parent->color = 'B';
|
||||
node->parent->parent->color = 'R';
|
||||
leftRotate(tree, node->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
tree->root->color = 'B';
|
||||
}
|
||||
|
||||
static void rbDeleteFixup(W_Bag * tree, W_Node * node)
|
||||
{
|
||||
W_Node *w;
|
||||
|
||||
while (node != tree->root && node->color == 'B') {
|
||||
if (IS_LEFT(node)) {
|
||||
w = node->parent->right;
|
||||
if (w->color == 'R') {
|
||||
w->color = 'B';
|
||||
node->parent->color = 'R';
|
||||
leftRotate(tree, node->parent);
|
||||
w = node->parent->right;
|
||||
}
|
||||
if (w->left->color == 'B' && w->right->color == 'B') {
|
||||
w->color = 'R';
|
||||
node = node->parent;
|
||||
} else {
|
||||
if (w->right->color == 'B') {
|
||||
w->left->color = 'B';
|
||||
w->color = 'R';
|
||||
rightRotate(tree, w);
|
||||
w = node->parent->right;
|
||||
}
|
||||
w->color = node->parent->color;
|
||||
node->parent->color = 'B';
|
||||
w->right->color = 'B';
|
||||
leftRotate(tree, node->parent);
|
||||
node = tree->root;
|
||||
}
|
||||
} else {
|
||||
w = node->parent->left;
|
||||
if (w->color == 'R') {
|
||||
w->color = 'B';
|
||||
node->parent->color = 'R';
|
||||
rightRotate(tree, node->parent);
|
||||
w = node->parent->left;
|
||||
}
|
||||
if (w->left->color == 'B' && w->right->color == 'B') {
|
||||
w->color = 'R';
|
||||
node = node->parent;
|
||||
} else {
|
||||
if (w->left->color == 'B') {
|
||||
w->right->color = 'B';
|
||||
w->color = 'R';
|
||||
leftRotate(tree, w);
|
||||
w = node->parent->left;
|
||||
}
|
||||
w->color = node->parent->color;
|
||||
node->parent->color = 'B';
|
||||
w->left->color = 'B';
|
||||
rightRotate(tree, node->parent);
|
||||
node = tree->root;
|
||||
}
|
||||
}
|
||||
}
|
||||
node->color = 'B';
|
||||
|
||||
}
|
||||
|
||||
static W_Node *treeMinimum(W_Node * node, W_Node * nil)
|
||||
{
|
||||
while (node->left != nil)
|
||||
node = node->left;
|
||||
return node;
|
||||
}
|
||||
|
||||
static W_Node *treeMaximum(W_Node * node, W_Node * nil)
|
||||
{
|
||||
while (node->right != nil)
|
||||
node = node->right;
|
||||
return node;
|
||||
}
|
||||
|
||||
static W_Node *treeSuccessor(W_Node * node, W_Node * nil)
|
||||
{
|
||||
W_Node *y;
|
||||
|
||||
if (node->right != nil) {
|
||||
return treeMinimum(node->right, nil);
|
||||
}
|
||||
y = node->parent;
|
||||
while (y != nil && node == y->right) {
|
||||
node = y;
|
||||
y = y->parent;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
static W_Node *treePredecessor(W_Node * node, W_Node * nil)
|
||||
{
|
||||
W_Node *y;
|
||||
|
||||
if (node->left != nil) {
|
||||
return treeMaximum(node->left, nil);
|
||||
}
|
||||
y = node->parent;
|
||||
while (y != nil && node == y->left) {
|
||||
node = y;
|
||||
y = y->parent;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
static W_Node *rbTreeDelete(W_Bag * tree, W_Node * node)
|
||||
{
|
||||
W_Node *nil = tree->nil;
|
||||
W_Node *x, *y;
|
||||
|
||||
if (node->left == nil || node->right == nil) {
|
||||
y = node;
|
||||
} else {
|
||||
y = treeSuccessor(node, nil);
|
||||
}
|
||||
|
||||
if (y->left != nil) {
|
||||
x = y->left;
|
||||
} else {
|
||||
x = y->right;
|
||||
}
|
||||
|
||||
x->parent = y->parent;
|
||||
|
||||
if (y->parent == nil) {
|
||||
tree->root = x;
|
||||
} else {
|
||||
if (IS_LEFT(y)) {
|
||||
y->parent->left = x;
|
||||
} else {
|
||||
y->parent->right = x;
|
||||
}
|
||||
}
|
||||
if (y != node) {
|
||||
node->index = y->index;
|
||||
node->data = y->data;
|
||||
}
|
||||
if (y->color == 'B') {
|
||||
rbDeleteFixup(tree, x);
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
static W_Node *treeSearch(W_Node * root, W_Node * nil, int index)
|
||||
{
|
||||
if (root == nil || root->index == index) {
|
||||
return root;
|
||||
}
|
||||
|
||||
if (index < root->index) {
|
||||
return treeSearch(root->left, nil, index);
|
||||
} else {
|
||||
return treeSearch(root->right, nil, index);
|
||||
}
|
||||
}
|
||||
|
||||
static W_Node *treeFind(W_Node * root, W_Node * nil, void *data)
|
||||
{
|
||||
W_Node *tmp;
|
||||
|
||||
if (root == nil || root->data == data)
|
||||
return root;
|
||||
|
||||
tmp = treeFind(root->left, nil, data);
|
||||
if (tmp != nil)
|
||||
return tmp;
|
||||
|
||||
tmp = treeFind(root->right, nil, data);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static char buf[512];
|
||||
|
||||
static void printNodes(W_Node * node, W_Node * nil, int depth)
|
||||
{
|
||||
if (node == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
printNodes(node->left, nil, depth + 1);
|
||||
|
||||
memset(buf, ' ', depth * 2);
|
||||
buf[depth * 2] = 0;
|
||||
if (IS_LEFT(node))
|
||||
printf("%s/(%2i\n", buf, node->index);
|
||||
else
|
||||
printf("%s\\(%2i\n", buf, node->index);
|
||||
|
||||
printNodes(node->right, nil, depth + 1);
|
||||
}
|
||||
|
||||
void PrintTree(WMBag * bag)
|
||||
{
|
||||
W_TreeBag *tree = (W_TreeBag *) bag->data;
|
||||
|
||||
printNodes(tree->root, tree->nil, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
WMBag *WMCreateTreeBag(void)
|
||||
{
|
||||
WMBag *bag;
|
||||
|
||||
bag = wmalloc(sizeof(WMBag));
|
||||
bag->nil = wmalloc(sizeof(W_Node));
|
||||
bag->nil->left = bag->nil->right = bag->nil->parent = bag->nil;
|
||||
bag->nil->index = WBNotFound;
|
||||
bag->root = bag->nil;
|
||||
|
||||
return bag;
|
||||
}
|
||||
|
||||
static int treeDeleteNode(WMBag * self, W_Node *ptr)
|
||||
{
|
||||
if (ptr != self->nil) {
|
||||
W_Node *tmp;
|
||||
|
||||
self->count--;
|
||||
|
||||
tmp = treeSuccessor(ptr, self->nil);
|
||||
while (tmp != self->nil) {
|
||||
tmp->index--;
|
||||
tmp = treeSuccessor(tmp, self->nil);
|
||||
}
|
||||
|
||||
ptr = rbTreeDelete(self, ptr);
|
||||
wfree(ptr);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *WMGetFromBag(WMBag * self, int index)
|
||||
{
|
||||
W_Node *node;
|
||||
|
||||
node = treeSearch(self->root, self->nil, index);
|
||||
if (node != self->nil)
|
||||
return node->data;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *WMReplaceInBag(WMBag * self, int index, void *item)
|
||||
{
|
||||
W_Node *ptr = treeSearch(self->root, self->nil, index);
|
||||
void *old = NULL;
|
||||
|
||||
if (item == NULL) {
|
||||
self->count--;
|
||||
ptr = rbTreeDelete(self, ptr);
|
||||
wfree(ptr);
|
||||
} else if (ptr != self->nil) {
|
||||
old = ptr->data;
|
||||
ptr->data = item;
|
||||
} else {
|
||||
W_Node *ptr;
|
||||
|
||||
ptr = wmalloc(sizeof(W_Node));
|
||||
|
||||
ptr->data = item;
|
||||
ptr->index = index;
|
||||
ptr->left = self->nil;
|
||||
ptr->right = self->nil;
|
||||
ptr->parent = self->nil;
|
||||
|
||||
rbTreeInsert(self, ptr);
|
||||
|
||||
self->count++;
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
static void deleteTree(WMBag * self, W_Node * node)
|
||||
{
|
||||
if (node == self->nil)
|
||||
return;
|
||||
|
||||
deleteTree(self, node->left);
|
||||
|
||||
deleteTree(self, node->right);
|
||||
|
||||
wfree(node);
|
||||
}
|
||||
|
||||
void WMEmptyBag(WMBag * self)
|
||||
{
|
||||
deleteTree(self, self->root);
|
||||
self->root = self->nil;
|
||||
self->count = 0;
|
||||
}
|
||||
|
||||
void WMFreeBag(WMBag * self)
|
||||
{
|
||||
WMEmptyBag(self);
|
||||
wfree(self->nil);
|
||||
wfree(self);
|
||||
}
|
||||
|
||||
void *WMBagFirst(WMBag * self, WMBagIterator * ptr)
|
||||
{
|
||||
W_Node *node;
|
||||
|
||||
node = treeMinimum(self->root, self->nil);
|
||||
|
||||
if (node == self->nil) {
|
||||
*ptr = NULL;
|
||||
return NULL;
|
||||
} else {
|
||||
*ptr = node;
|
||||
return node->data;
|
||||
}
|
||||
}
|
||||
|
||||
void *WMBagLast(WMBag * self, WMBagIterator * ptr)
|
||||
{
|
||||
|
||||
W_Node *node;
|
||||
|
||||
node = treeMaximum(self->root, self->nil);
|
||||
|
||||
if (node == self->nil) {
|
||||
*ptr = NULL;
|
||||
return NULL;
|
||||
} else {
|
||||
*ptr = node;
|
||||
return node->data;
|
||||
}
|
||||
}
|
||||
|
||||
void *WMBagNext(WMBag * self, WMBagIterator * ptr)
|
||||
{
|
||||
W_Node *node;
|
||||
|
||||
if (*ptr == NULL)
|
||||
return NULL;
|
||||
|
||||
node = treeSuccessor(*ptr, self->nil);
|
||||
|
||||
if (node == self->nil) {
|
||||
*ptr = NULL;
|
||||
return NULL;
|
||||
} else {
|
||||
*ptr = node;
|
||||
return node->data;
|
||||
}
|
||||
}
|
||||
|
||||
void *WMBagPrevious(WMBag * self, WMBagIterator * ptr)
|
||||
{
|
||||
W_Node *node;
|
||||
|
||||
if (*ptr == NULL)
|
||||
return NULL;
|
||||
|
||||
node = treePredecessor(*ptr, self->nil);
|
||||
|
||||
if (node == self->nil) {
|
||||
*ptr = NULL;
|
||||
return NULL;
|
||||
} else {
|
||||
*ptr = node;
|
||||
return node->data;
|
||||
}
|
||||
}
|
||||
|
||||
void *WMBagIteratorAtIndex(WMBag * self, int index, WMBagIterator * ptr)
|
||||
{
|
||||
W_Node *node;
|
||||
|
||||
node = treeSearch(self->root, self->nil, index);
|
||||
|
||||
if (node == self->nil) {
|
||||
*ptr = NULL;
|
||||
return NULL;
|
||||
} else {
|
||||
*ptr = node;
|
||||
return node->data;
|
||||
}
|
||||
}
|
||||
@@ -109,16 +109,16 @@ void Shutdown(WShutdownMode mode)
|
||||
}
|
||||
}
|
||||
|
||||
static void restoreWindows(WMBag * bag, WMBagIterator iter)
|
||||
static void restoreWindows(WMBag * bag, WMBagIterator *iter)
|
||||
{
|
||||
WCoreWindow *next;
|
||||
WCoreWindow *core;
|
||||
WWindow *wwin;
|
||||
|
||||
if (iter == NULL) {
|
||||
core = WMBagFirst(bag, &iter);
|
||||
if (*iter < 0) {
|
||||
core = WMBagFirst(bag, iter);
|
||||
} else {
|
||||
core = WMBagNext(bag, &iter);
|
||||
core = WMBagNext(bag, iter);
|
||||
}
|
||||
|
||||
if (core == NULL)
|
||||
@@ -168,7 +168,8 @@ void RestoreDesktop(WScreen * scr)
|
||||
wDestroyInspectorPanels();
|
||||
|
||||
/* reparent windows back to the root window, keeping the stacking order */
|
||||
restoreWindows(scr->stacking_list, NULL);
|
||||
WMBagIterator iter = -1;
|
||||
restoreWindows(scr->stacking_list, &iter);
|
||||
|
||||
XUngrabServer(dpy);
|
||||
XSetInputFocus(dpy, PointerRoot, RevertToParent, CurrentTime);
|
||||
|
||||
@@ -2,6 +2,7 @@ AUTOMAKE_OPTIONS =
|
||||
|
||||
RUST_SOURCES = \
|
||||
src/array.rs \
|
||||
src/bag.rs \
|
||||
src/data.rs \
|
||||
src/defines.c \
|
||||
src/defines.rs \
|
||||
|
||||
390
wutil-rs/src/bag.rs
Normal file
390
wutil-rs/src/bag.rs
Normal file
@@ -0,0 +1,390 @@
|
||||
//! Simple sorted set.
|
||||
//!
|
||||
//! ## Rust rewrite notes
|
||||
//!
|
||||
//! This was originally a full-blown red-black tree, but it was really only used
|
||||
//! to keep a sorted list. It has been rewritten as a sorted `Vec`. We
|
||||
//! technically no longer have O(log(n)) insertion time. Given set sizes and
|
||||
//! actual execution time, that shouldn't matter.
|
||||
//!
|
||||
//! Prefer a proper Rust collection over this for new code.
|
||||
|
||||
use std::{
|
||||
ffi::{c_int, c_void},
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Bag {
|
||||
inner: Vec<(c_int, NonNull<c_void>)>,
|
||||
}
|
||||
|
||||
/// Sentinel iterator value. In C, just check for negative values.
|
||||
pub const NOT_FOUND: c_int = -1;
|
||||
|
||||
impl Bag {
|
||||
/// Returns `Ok(index)` if an item keyed by `key` is in `self`, else
|
||||
/// `Err(index)` if an item keyed by `key` could be inserted at `index`.
|
||||
fn search(&self, key: c_int) -> Result<usize, usize> {
|
||||
// self.inner.binary_search_by(|x| key.cmp(&x.0))
|
||||
self.inner.binary_search_by_key(&key, |(key, _)| *key)
|
||||
}
|
||||
|
||||
/// Returns the index of `self.inner` where `key` is found.
|
||||
fn find_index(&self, key: c_int) -> Option<usize> {
|
||||
self.search(key).ok()
|
||||
}
|
||||
|
||||
/// Returns the value associated with `key`.
|
||||
fn find_value(&self, key: c_int) -> Option<NonNull<c_void>> {
|
||||
let i = self.find_index(key)?;
|
||||
self.inner.get(i).copied().map(|(_, value)| value)
|
||||
}
|
||||
|
||||
/// Removes any value associated with `key`.
|
||||
fn remove(&mut self, key: c_int) {
|
||||
let Some(i) = self.find_index(key) else {
|
||||
return;
|
||||
};
|
||||
self.inner.remove(i);
|
||||
}
|
||||
|
||||
/// Sets a value associated with `key` to `value`. Clobbers any extant value.
|
||||
fn set(&mut self, key: c_int, value: NonNull<c_void>) {
|
||||
match self.search(key) {
|
||||
Ok(i) => self.inner[i] = (key, value),
|
||||
Err(i) => self.inner.insert(i, (key, value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod ffi {
|
||||
use super::{Bag, NOT_FOUND};
|
||||
|
||||
use std::{
|
||||
ffi::{c_int, c_void},
|
||||
ptr::{self, NonNull},
|
||||
};
|
||||
|
||||
/// Basic constructor. Free with [`WMFreeBag`].
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMCreateTreeBag() -> *mut Bag {
|
||||
Box::leak(Box::new(Bag::default()))
|
||||
}
|
||||
|
||||
/// Retrieves the value associated with `key`, or null.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMGetFromBag(bag: *mut Bag, key: c_int) -> *mut c_void {
|
||||
if bag.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
unsafe {
|
||||
(*bag)
|
||||
.find_value(key)
|
||||
.map(|p| p.as_ptr())
|
||||
.unwrap_or(ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the value associated with `key` to `item`. If `item` is null,
|
||||
/// removes any extant value.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMSetInBag(bag: *mut Bag, key: c_int, item: *mut c_void) {
|
||||
if bag.is_null() {
|
||||
return;
|
||||
}
|
||||
let bag = unsafe { &mut *bag };
|
||||
|
||||
if let Some(item) = NonNull::new(item) {
|
||||
bag.set(key, item);
|
||||
} else {
|
||||
bag.remove(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the contents of `bag`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMEmptyBag(bag: *mut Bag) {
|
||||
if bag.is_null() {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
(*bag).inner.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// Deletes `bag`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMFreeBag(bag: *mut Bag) {
|
||||
if bag.is_null() {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
let _ = Box::from_raw(bag);
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes `ptr` to the first element of `bag` and returns that
|
||||
/// element. Sets `ptr` to [`NOT_FOUND`] and returns null if `bag` is empty.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMBagFirst(bag: *mut Bag, ptr: *mut c_int) -> *mut c_void {
|
||||
if ptr.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let ptr = unsafe { &mut *ptr };
|
||||
|
||||
if bag.is_null() {
|
||||
*ptr = NOT_FOUND;
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let bag = unsafe { &mut *bag };
|
||||
|
||||
if let Some((_, value)) = bag.inner.first() {
|
||||
*ptr = 0;
|
||||
value.as_ptr()
|
||||
} else {
|
||||
*ptr = NOT_FOUND;
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes `ptr` to the last element of `bag` and returns that
|
||||
/// element. Sets `ptr` to [`NOT_FOUND`] and returns null if `bag` is empty.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMBagLast(bag: *mut Bag, ptr: *mut c_int) -> *mut c_void {
|
||||
if ptr.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let ptr = unsafe { &mut *ptr };
|
||||
|
||||
if bag.is_null() {
|
||||
*ptr = NOT_FOUND;
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let bag = unsafe { &mut *bag };
|
||||
|
||||
if let Some((_, value)) = bag.inner.last() {
|
||||
*ptr = (bag.inner.len() - 1) as c_int;
|
||||
value.as_ptr()
|
||||
} else {
|
||||
*ptr = NOT_FOUND;
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Advances `ptr` to the next element of `bag` and returns it. Sets `ptr`
|
||||
/// to [`NOT_FOUND`] and returns null if `ptr` is already at the end of
|
||||
/// `bag`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMBagNext(bag: *mut Bag, ptr: *mut c_int) -> *mut c_void {
|
||||
if ptr.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let ptr = unsafe { &mut *ptr };
|
||||
|
||||
if bag.is_null() {
|
||||
*ptr = NOT_FOUND;
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let bag = unsafe { &mut *bag };
|
||||
|
||||
if *ptr < 0 {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
*ptr += 1;
|
||||
if let Some((_, value)) = bag.inner.get(*ptr as usize) {
|
||||
value.as_ptr()
|
||||
} else {
|
||||
*ptr = NOT_FOUND;
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrements `ptr` to the previous element of `bag` and returns it. Sets `ptr`
|
||||
/// to [`NOT_FOUND`] and returns null if `ptr` is already at the beginning of
|
||||
/// `bag`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMBagPrevious(bag: *mut Bag, ptr: *mut c_int) -> *mut c_void {
|
||||
if ptr.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let ptr = unsafe { &mut *ptr };
|
||||
|
||||
if bag.is_null() {
|
||||
*ptr = NOT_FOUND;
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let bag = unsafe { &mut *bag };
|
||||
|
||||
if *ptr <= 0 {
|
||||
*ptr = NOT_FOUND;
|
||||
return ptr::null_mut();
|
||||
}
|
||||
*ptr -= 1;
|
||||
if let Some((_, value)) = bag.inner.get(*ptr as usize) {
|
||||
value.as_ptr()
|
||||
} else {
|
||||
*ptr = NOT_FOUND;
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets `ptr` to the element of `bag` with `key` and returns the associated
|
||||
/// value. Sets `ptr` to [`NOT_FOUND`] and returns null if there is no such
|
||||
/// element.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn WMBagIteratorAtIndex(
|
||||
bag: *mut Bag,
|
||||
key: c_int,
|
||||
ptr: *mut c_int,
|
||||
) -> *mut c_void {
|
||||
if ptr.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let ptr = unsafe { &mut *ptr };
|
||||
|
||||
if bag.is_null() {
|
||||
*ptr = NOT_FOUND;
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let bag = unsafe { &mut *bag };
|
||||
|
||||
if key < 0 {
|
||||
*ptr = NOT_FOUND;
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
if let Some(index) = bag.find_index(key) {
|
||||
*ptr = index as c_int;
|
||||
bag.inner[index].1.as_ptr()
|
||||
} else {
|
||||
*ptr = NOT_FOUND;
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{ffi, Bag, NOT_FOUND};
|
||||
|
||||
use std::{
|
||||
ffi::{c_int, c_void},
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
fn void_of<T>(t: &mut T) -> NonNull<c_void> {
|
||||
NonNull::new(t as *mut _ as *mut c_void).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_out_of_order() {
|
||||
let mut b = Bag::default();
|
||||
let mut x = 3u16;
|
||||
let mut y = 4u16;
|
||||
let mut z = 5u16;
|
||||
b.set(7, void_of(&mut z));
|
||||
b.set(3, void_of(&mut y));
|
||||
b.set(5, void_of(&mut x));
|
||||
|
||||
assert_eq!(
|
||||
b.inner,
|
||||
&[
|
||||
(3, void_of(&mut y)),
|
||||
(5, void_of(&mut x)),
|
||||
(7, void_of(&mut z))
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterate_forward() {
|
||||
let mut b = Bag::default();
|
||||
let mut x = 3u16;
|
||||
let mut y = 4u16;
|
||||
let mut z = 5u16;
|
||||
b.set(7, void_of(&mut z));
|
||||
b.set(3, void_of(&mut y));
|
||||
b.set(5, void_of(&mut x));
|
||||
|
||||
let mut iterator: c_int = NOT_FOUND;
|
||||
unsafe {
|
||||
assert_eq!(
|
||||
ffi::WMBagFirst(&mut b, &mut iterator),
|
||||
void_of(&mut y).as_ptr()
|
||||
);
|
||||
assert_eq!(iterator, 0);
|
||||
assert_eq!(
|
||||
ffi::WMBagNext(&mut b, &mut iterator),
|
||||
void_of(&mut x).as_ptr()
|
||||
);
|
||||
assert_eq!(iterator, 1);
|
||||
assert_eq!(
|
||||
ffi::WMBagNext(&mut b, &mut iterator),
|
||||
void_of(&mut z).as_ptr()
|
||||
);
|
||||
assert_eq!(iterator, 2);
|
||||
assert!(ffi::WMBagNext(&mut b, &mut iterator).is_null());
|
||||
assert_eq!(iterator, NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterate_backward() {
|
||||
let mut b = Bag::default();
|
||||
let mut x = 3u16;
|
||||
let mut y = 4u16;
|
||||
let mut z = 5u16;
|
||||
b.set(7, void_of(&mut z));
|
||||
b.set(3, void_of(&mut y));
|
||||
b.set(5, void_of(&mut x));
|
||||
|
||||
let mut iterator: c_int = NOT_FOUND;
|
||||
unsafe {
|
||||
assert_eq!(
|
||||
ffi::WMBagLast(&mut b, &mut iterator),
|
||||
void_of(&mut z).as_ptr()
|
||||
);
|
||||
assert_eq!(iterator, 2);
|
||||
assert_eq!(
|
||||
ffi::WMBagPrevious(&mut b, &mut iterator),
|
||||
void_of(&mut x).as_ptr()
|
||||
);
|
||||
assert_eq!(iterator, 1);
|
||||
assert_eq!(
|
||||
ffi::WMBagPrevious(&mut b, &mut iterator),
|
||||
void_of(&mut y).as_ptr()
|
||||
);
|
||||
assert_eq!(iterator, 0);
|
||||
assert!(ffi::WMBagPrevious(&mut b, &mut iterator).is_null());
|
||||
assert_eq!(iterator, NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn find_iterate() {
|
||||
let mut b = Bag::default();
|
||||
let mut x = 3u16;
|
||||
let mut y = 4u16;
|
||||
let mut z = 5u16;
|
||||
b.set(7, void_of(&mut z));
|
||||
b.set(3, void_of(&mut y));
|
||||
b.set(5, void_of(&mut x));
|
||||
|
||||
let mut iterator: c_int = NOT_FOUND;
|
||||
unsafe {
|
||||
assert_eq!(
|
||||
ffi::WMBagIteratorAtIndex(&mut b, 5, &mut iterator),
|
||||
void_of(&mut x).as_ptr()
|
||||
);
|
||||
assert_eq!(iterator, 1);
|
||||
assert_eq!(
|
||||
ffi::WMBagNext(&mut b, &mut iterator),
|
||||
void_of(&mut z).as_ptr()
|
||||
);
|
||||
assert_eq!(iterator, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod array;
|
||||
pub mod bag;
|
||||
pub mod data;
|
||||
pub mod defines;
|
||||
pub mod find_file;
|
||||
|
||||
Reference in New Issue
Block a user