/* * Tree data structure * * Copyright (C) 2017 Patrick McDermott * * This file is part of Marquee. * * Marquee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Marquee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Marquee. If not, see . */ #include "tree.h" #include MqTree * mq_tree_insert_root_allocated(MqTree *node, gpointer data) { node->root = node; node->data = data; return node; } static void update_sizes(MqTree *node, gint step) { if (node) { node->size += step; update_sizes(node->parent, step); } } static void update_positions(MqTree *node, gint step) { for (; node; node = node->next) { node->position += step; if (node->first_child) { update_positions(node->first_child, step); } if (node->parent && node->parent->next) { update_positions(node->parent->next, step); } } } MqTree * mq_tree_insert_child_allocated(MqTree *node, MqTree *parent, gpointer data) { /* Copy ancestor pointers. */ node->root = parent->root; node->parent = parent; if (parent->last_child) { /* Parent has children, so get position from sibling and append * to list of children. */ node->position = parent->last_child->position; node->prev = parent->last_child; parent->last_child->next = node; } else { /* Parent has no children, so get position from parent and add * first child to parent. */ node->position = parent->position; parent->first_child = node; } parent->last_child = node; update_positions(node, 1); node->size = 0; update_sizes(node, 1); node->data = data; return node; } MqTree * mq_tree_insert_sibling_allocated(MqTree *node, MqTree *sibling, gpointer data) { /* Copy ancestor pointers. */ node->root = sibling->root; node->parent = sibling->parent; /* Link to next sibling, if any. */ if (sibling->next) { node->next = sibling->next; sibling->next->prev = node; } /* Link to previous sibling. */ node->prev = sibling; sibling->next = node; node->size = 0; update_sizes(node, 1); node->position = sibling->position; update_positions(node, 1); node->data = data; return node; } void mq_tree_remove(MqTree *node) { /* TODO */ node = node; } MqTree * mq_tree_seek(MqTree *node, gint offset) { /* XXX: Only forward seeking from a tree's root is supported. */ g_assert(node && node->position == 0); g_assert(offset > 0); /* Skip forward to the containing subtree. */ while (node && node->position + node->size <= offset) { node = node->next; } /* Check whether we've gone past the end of the tree. */ if (!node) { return NULL; } /* Check whether the sibling we've reached is the node we want. */ if (node->position == offset) { return node; } /* Recurse down the subtree. */ return mq_tree_seek(node->first_child, offset); } static gboolean foreach(MqTree *node, gboolean (*cb)(MqTree *node, va_list ap), va_list ap) { va_list aq; gboolean ret; ret = MQ_TREE_CONTINUE; for (; node; node = node->next) { /* XXX: Warning: Does not skip root node */ va_copy(ap, aq); ret = cb(node, aq); va_end(aq); if (ret == MQ_TREE_STOP) { break; } if (node->first_child) { va_copy(ap, aq); ret = foreach(node->first_child, cb, aq); va_end(aq); if (ret == MQ_TREE_STOP) { break; } } if (node->parent && node->parent->next) { va_copy(ap, aq); ret = foreach(node->parent->next, cb, aq); va_end(aq); if (ret == MQ_TREE_STOP) { break; } } } return ret; } void mq_tree_foreach(MqTree *node, gboolean (*cb)(MqTree *node, va_list ap), ...) { va_list ap; va_start(ap, cb); foreach(node->root->first_child, cb, ap); va_end(ap); } static gboolean foreach_child(MqTree *node, gboolean (*cb)(MqTree *node, va_list ap), va_list ap) { va_list aq; gboolean ret; ret = MQ_TREE_CONTINUE; for (node = node->first_child; node; node = node->next) { va_copy(ap, aq); ret = cb(node, aq); va_end(aq); if (ret == MQ_TREE_STOP) { break; } } return ret; } void mq_tree_foreach_child(MqTree *node, gboolean (*cb)(MqTree *node, va_list ap), ...) { va_list ap; va_start(ap, cb); foreach_child(node->root->first_child, cb, ap); va_end(ap); }