/* * Copyright (c) 2015, Andrea Mazzoleni. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** \file * AVL tree. * * This tree is a standard AVL tree implementation that stores elements in the * order defined by the comparison function. * * As difference than other tommy containers, duplicate elements cannot be inserted. * * To initialize a tree you have to call tommy_tree_init() specifying a comparison * function that will define the order in the tree. * * \code * tommy_tree tree; * * tommy_tree_init(&tree, cmp); * \endcode * * To insert elements in the tree you have to call tommy_tree_insert() for * each element. * In the insertion call you have to specify the address of the node and the * address of the object. * The address of the object is used to initialize the tommy_node::data field * of the node. * * \code * struct object { * int value; * // other fields * tommy_tree_node node; * }; * * struct object* obj = malloc(sizeof(struct object)); // creates the object * * obj->value = ...; // initializes the object * * tommy_tree_insert(&tree, &obj->node, obj); // inserts the object * \endcode * * To find and element in the tree you have to call tommy_tree_search() providing * the key to search. * * \code * struct object value_to_find = { 1 }; * struct object* obj = tommy_tree_search(&tree, &value_to_find); * if (!obj) { * // not found * } else { * // found * } * \endcode * * To remove an element from the tree you have to call tommy_tree_remove() * providing the key to search and remove. * * \code * struct object value_to_remove = { 1 }; * struct object* obj = tommy_tree_remove(&tree, &value_to_remove); * if (obj) { * free(obj); // frees the object allocated memory * } * \endcode * * To destroy the tree you have to remove or destroy all the contained elements. * The tree itself doesn't have or need a deallocation function. * * If you need to iterate over all the elements in the tree, you can use * tommy_tree_foreach() or tommy_tree_foreach_arg(). * If you need a more precise control with a real iteration, you have to insert * all the elements also in a ::tommy_list, and use the list to iterate. * See the \ref multiindex example for more detail. */ #ifndef __TOMMYTREE_H #define __TOMMYTREE_H #include "tommytypes.h" /******************************************************************************/ /* tree */ /** * Tree node. * This is the node that you have to include inside your objects. */ typedef tommy_node tommy_tree_node; /** * Tree container type. * \note Don't use internal fields directly, but access the container only using functions. */ typedef struct tommy_tree_struct { tommy_tree_node* root; /**< Root node. */ tommy_compare_func* cmp; /**< Comparison function. */ tommy_size_t count; /**< Number of elements. */ } tommy_tree; /** * Initializes the tree. * \param cmp The comparison function that defines the order in the tree. */ void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp); /** * Inserts an element in the tree. * If the element is already present, it's not inserted again. * Check the return value to identify if the element was already present or not. * You have to provide the pointer of the node embedded into the object and * the pointer to the object. * \param node Pointer to the node embedded into the object to insert. * \param data Pointer to the object to insert. * \return The element in the tree. Either the already existing one, or the one just inserted. */ void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data); /** * Searches and removes an element. * If the element is not found, 0 is returned. * \param data Element used for comparison. * \return The removed element, or 0 if not found. */ void* tommy_tree_remove(tommy_tree* tree, void* data); /** * Searches an element in the tree. * If the element is not found, 0 is returned. * \param data Element used for comparison. * \return The first element found, or 0 if none. */ void* tommy_tree_search(tommy_tree* tree, void* data); /** * Searches an element in the tree with a specific comparison function. * * Like tommy_tree_search() but you can specify a different comparison function. * Note that this function must define a suborder of the original one. * * The ::data argument will be the first argument of the comparison function, * and it can be of a different type of the objects in the tree. */ void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* cmp_arg); /** * Removes an element from the tree. * You must already have the address of the element to remove. * \return The tommy_node::data field of the node removed. */ void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node); /** * Calls the specified function for each element in the tree. * * The elements are processed in order. * * You cannot add or remove elements from the inside of the callback, * but can use it to deallocate them. * * \code * tommy_tree tree; * * // initializes the tree * tommy_tree_init(&tree, cmp); * * ... * * // creates an object * struct object* obj = malloc(sizeof(struct object)); * * ... * * // insert it in the tree * tommy_tree_insert(&tree, &obj->node, obj); * * ... * * // deallocates all the objects iterating the tree * tommy_tree_foreach(&tree, free); * \endcode */ void tommy_tree_foreach(tommy_tree* tree, tommy_foreach_func* func); /** * Calls the specified function with an argument for each element in the tree. */ void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void* arg); /** * Gets the number of elements. */ tommy_inline tommy_size_t tommy_tree_count(tommy_tree* tree) { return tree->count; } /** * Gets the size of allocated memory. * It includes the size of the ::tommy_tree_node of the stored elements. */ tommy_size_t tommy_tree_memory_usage(tommy_tree* tree); #endif