summaryrefslogtreecommitdiffstats
path: root/core/set.h
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
committerJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
commit0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch)
tree276c4d099e178eb67fbd14f61d77b05e3808e9e3 /core/set.h
parent0e49da1687bc8192ed210947da52c9e5c5f301bb (diff)
downloadredot-engine-0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac.tar.gz
GODOT IS OPEN SOURCE
Diffstat (limited to 'core/set.h')
-rw-r--r--core/set.h630
1 files changed, 630 insertions, 0 deletions
diff --git a/core/set.h b/core/set.h
new file mode 100644
index 0000000000..d87f635577
--- /dev/null
+++ b/core/set.h
@@ -0,0 +1,630 @@
+/*************************************************************************/
+/* set.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef SET_H
+#define SET_H
+
+#include "typedefs.h"
+#include "os/memory.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+
+// based on the very nice implementation of rb-trees by:
+// http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
+
+template <class T,class C=Comparator<T>,class A=DefaultAllocator >
+class Set {
+
+ enum Color {
+ RED,
+ BLACK
+ };
+ struct _Data;
+public:
+
+
+
+ class Element {
+
+ private:
+ friend class Set<T,C,A>;
+ int color;
+ Element* right;
+ Element* left;
+ Element* parent;
+ Element* _next;
+ Element* _prev;
+ T value;
+ //_Data *data;
+
+ public:
+
+ const Element *next() const {
+
+ return _next;
+ }
+ Element *next() {
+
+ return _next;
+ }
+ const Element *prev() const {
+
+ return _prev;
+ }
+ Element *prev() {
+
+ return _prev;
+ }
+ const T& get() const {
+ return value;
+ };
+ Element() {
+ color=RED;
+ right=NULL;
+ left=NULL;
+ parent=NULL;
+ _next=NULL;
+ _prev=NULL;
+ };
+ };
+
+
+private:
+
+ struct _Data {
+
+ Element* _root;
+ Element* _nil;
+ int size_cache;
+
+
+ _Data() {
+#ifdef GLOBALNIL_DISABLED
+ _nil = memnew_allocator( Element,A );
+ _nil->parent=_nil->left=_nil->right=_nil;
+ _nil->color=BLACK;
+#else
+
+ _nil=(Element*)&_GlobalNilClass::_nil;
+#endif
+ _root = NULL;
+
+ size_cache=0;
+ }
+
+ void _create_root() {
+
+ _root = memnew_allocator( Element,A );
+ _root->parent=_root->left=_root->right=_nil;
+ _root->color=BLACK;
+ }
+
+ void _free_root() {
+
+ if (_root) {
+ memdelete_allocator<Element,A>(_root);
+ _root=NULL;
+ }
+ }
+
+ ~_Data() {
+
+ _free_root();
+#ifdef GLOBALNIL_DISABLED
+ memdelete_allocator<Element,A>(_nil);
+#endif
+// memdelete_allocator<Element,A>(_root);
+ }
+ };
+
+ _Data _data;
+
+ inline void _set_color(Element *p_node, int p_color) {
+
+ ERR_FAIL_COND( p_node == _data._nil && p_color == RED );
+ p_node->color=p_color;
+ }
+ inline void _rotate_left(Element *p_node) {
+
+ Element *r=p_node->right;
+ p_node->right=r->left;
+ if (r->left != _data._nil )
+ r->left->parent=p_node;
+ r->parent=p_node->parent;
+ if (p_node==p_node->parent->left)
+ p_node->parent->left=r;
+ else
+ p_node->parent->right=r;
+
+ r->left=p_node;
+ p_node->parent=r;
+
+ }
+
+ inline void _rotate_right(Element *p_node) {
+
+ Element *l=p_node->left;
+ p_node->left=l->right;
+ if (l->right != _data._nil)
+ l->right->parent=p_node;
+ l->parent=p_node->parent;
+ if (p_node==p_node->parent->right)
+ p_node->parent->right=l;
+ else
+ p_node->parent->left=l;
+
+ l->right=p_node;
+ p_node->parent=l;
+
+ }
+
+ inline Element* _successor(Element *p_node) const {
+
+ Element *node=p_node;
+
+ if (node->right != _data._nil) {
+
+ node=node->right;
+ while(node->left != _data._nil) { /* returns the minium of the right subtree of node */
+ node=node->left;
+ }
+ return node;
+ } else {
+
+ while(node == node->parent->right) {
+ node=node->parent;
+ }
+ if (node->parent == _data._root)
+ return NULL;
+ return node->parent;
+ }
+ }
+
+ inline Element* _predecessor(Element *p_node) const {
+ Element *node=p_node;
+
+ if (node->left != _data._nil) {
+
+ node=node->left;
+ while(node->right != _data._nil) { /* returns the minium of the left subtree of node */
+ node=node->right;
+ }
+ return node;
+ } else {
+
+ while(node == node->parent->left) {
+ if (node->parent == _data._root)
+ return NULL;
+
+ node=node->parent;
+ }
+ return node->parent;
+ }
+ }
+
+
+ Element *_find(const T& p_value) const {
+
+ Element *node = _data._root->left;
+ C less;
+
+ while(node!=_data._nil) {
+
+ if (less(p_value,node->value))
+ node=node->left;
+ else if (less(node->value,p_value))
+ node=node->right;
+ else
+ break; // found
+ }
+
+ return (node!=_data._nil)?node:NULL;
+ }
+
+
+ Element *_insert(const T& p_value, bool& r_exists) {
+
+ Element *new_parent=_data._root;
+ Element *node = _data._root->left;
+ C less;
+
+ while (node!=_data._nil) {
+
+ new_parent=node;
+
+ if (less(p_value,node->value))
+ node=node->left;
+ else if (less(node->value,p_value))
+ node=node->right;
+ else {
+ r_exists=true;
+ return node;
+ }
+ }
+
+ Element *new_node = memnew_allocator( Element,A );
+
+ new_node->parent=new_parent;
+ new_node->right=_data._nil;
+ new_node->left=_data._nil;
+ new_node->value=p_value;
+// new_node->data=_data;
+ if (new_parent==_data._root || less(p_value,new_parent->value)) {
+
+ new_parent->left=new_node;
+ } else {
+ new_parent->right=new_node;
+ }
+
+ r_exists=false;
+
+ new_node->_next=_successor(new_node);
+ new_node->_prev=_predecessor(new_node);
+ if (new_node->_next)
+ new_node->_next->_prev=new_node;
+ if (new_node->_prev)
+ new_node->_prev->_next=new_node;
+
+
+ return new_node;
+ }
+
+ Element * _insert_rb(const T& p_value) {
+
+ bool exists=false;
+ Element *new_node = _insert(p_value,exists);
+ if (exists)
+ return new_node;
+
+ Element *node=new_node;
+ _data.size_cache++;
+
+ while(node->parent->color==RED) {
+
+ if (node->parent == node->parent->parent->left) {
+
+ Element *aux=node->parent->parent->right;
+
+ if (aux->color==RED) {
+ _set_color(node->parent,BLACK);
+ _set_color(aux,BLACK);
+ _set_color(node->parent->parent,RED);
+ node=node->parent->parent;
+ } else {
+ if (node == node->parent->right) {
+ node=node->parent;
+ _rotate_left(node);
+ }
+ _set_color(node->parent,BLACK);
+ _set_color(node->parent->parent,RED);
+ _rotate_right(node->parent->parent);
+ }
+ } else {
+ Element *aux=node->parent->parent->left;
+
+ if (aux->color==RED) {
+ _set_color(node->parent,BLACK);
+ _set_color(aux,BLACK);
+ _set_color(node->parent->parent,RED);
+ node=node->parent->parent;
+ } else {
+ if (node == node->parent->left) {
+ node=node->parent;
+ _rotate_right(node);
+ }
+ _set_color(node->parent,BLACK);
+ _set_color(node->parent->parent,RED);
+ _rotate_left(node->parent->parent);
+ }
+ }
+ }
+ _set_color(_data._root->left,BLACK);
+ return new_node;
+ }
+
+ void _erase_fix(Element *p_node) {
+
+ Element *root = _data._root->left;
+ Element *node=p_node;
+
+
+ while( (node->color==BLACK) && (root != node)) {
+ if (node == node->parent->left) {
+ Element *aux=node->parent->right;
+ if (aux->color==RED) {
+ _set_color(aux,BLACK);
+ _set_color(node->parent,RED);
+ _rotate_left(node->parent);
+ aux=node->parent->right;
+ }
+ if ( (aux->right->color==BLACK) && (aux->left->color==BLACK) ) {
+ _set_color(aux,RED);
+ node=node->parent;
+ } else {
+ if (aux->right->color==BLACK) {
+ _set_color(aux->left,BLACK);
+ _set_color(aux,RED);
+ _rotate_right(aux);
+ aux=node->parent->right;
+ }
+ _set_color(aux,node->parent->color);
+ _set_color(node->parent,BLACK);
+ _set_color(aux->right,BLACK);
+ _rotate_left(node->parent);
+ node=root; /* this is to exit while loop */
+ }
+ } else { /* the code below is has left and right switched from above */
+ Element *aux=node->parent->left;
+ if (aux->color==RED) {
+ _set_color(aux,BLACK);
+ _set_color(node->parent,RED);;
+ _rotate_right(node->parent);
+ aux=node->parent->left;
+ }
+ if ( (aux->right->color==BLACK) && (aux->left->color==BLACK) ) {
+ _set_color(aux,RED);
+ node=node->parent;
+ } else {
+ if (aux->left->color==BLACK) {
+ _set_color(aux->right,BLACK);
+ _set_color(aux,RED);
+ _rotate_left(aux);
+ aux=node->parent->left;
+ }
+ _set_color(aux,node->parent->color);
+ _set_color(node->parent,BLACK);
+ _set_color(aux->left,BLACK);
+ _rotate_right(node->parent);
+ node=root;
+ }
+ }
+ }
+
+ _set_color(node,BLACK);
+
+ ERR_FAIL_COND(_data._nil->color!=BLACK);
+ }
+
+ void _erase(Element *p_node) {
+
+
+ Element *rp= ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : _successor(p_node);
+ if (!rp)
+ rp=_data._nil;
+ Element *node= (rp->left == _data._nil) ? rp->right : rp->left;
+
+ if (_data._root == (node->parent=rp->parent) ) {
+ _data._root->left=node;
+ } else {
+ if (rp == rp->parent->left) {
+ rp->parent->left=node;
+ } else {
+ rp->parent->right=node;
+ }
+ }
+
+ if (rp != p_node) {
+
+ ERR_FAIL_COND( rp == _data._nil );
+
+ if (rp->color==BLACK)
+ _erase_fix(node);
+
+
+ rp->left=p_node->left;
+ rp->right=p_node->right;
+ rp->parent=p_node->parent;
+ rp->color=p_node->color;
+ p_node->left->parent=rp;
+ p_node->right->parent=rp;
+
+ if (p_node == p_node->parent->left) {
+ p_node->parent->left=rp;
+ } else {
+ p_node->parent->right=rp;
+ }
+ } else {
+ if (p_node->color==BLACK)
+ _erase_fix(node);
+
+ }
+
+
+ if (p_node->_next)
+ p_node->_next->_prev=p_node->_prev;
+ if (p_node->_prev)
+ p_node->_prev->_next=p_node->_next;
+
+ memdelete_allocator<Element,A>(p_node);
+ _data.size_cache--;
+ ERR_FAIL_COND( _data._nil->color==RED );
+ }
+
+
+ void _calculate_depth(Element *p_element,int &max_d,int d) const {
+
+ if (p_element==_data._nil) {
+ return;
+ }
+ _calculate_depth(p_element->left,max_d,d+1);
+ _calculate_depth(p_element->right,max_d,d+1);
+ if (d>max_d)
+ max_d=d;
+ }
+
+ void _cleanup_tree(Element *p_element) {
+
+ if (p_element==_data._nil)
+ return;
+
+ _cleanup_tree(p_element->left);
+ _cleanup_tree(p_element->right);
+ memdelete_allocator<Element,A>( p_element );
+ }
+
+ void _copy_from( const Set& p_set) {
+
+ clear();
+ // not the fastest way, but safeset to write.
+ for(Element *I=p_set.front();I;I=I->next()) {
+
+ insert(I->get());
+ }
+ }
+public:
+
+ const Element *find(const T& p_value) const {
+
+ if (!_data._root)
+ return NULL;
+
+ const Element *res=_find(p_value);
+ return res;
+ }
+
+ Element *find(const T& p_value) {
+
+ if (!_data._root)
+ return NULL;
+ Element *res=_find(p_value);
+ return res;
+ }
+
+ bool has(const T& p_value) const {
+
+ if (!_data._root)
+ return false;
+ return find(p_value)!=NULL;
+ }
+
+ Element *insert(const T& p_value) {
+
+ if (!_data._root)
+ _data._create_root();
+ return _insert_rb(p_value);
+
+ }
+
+ void erase(Element* p_element) {
+
+ if (!_data._root)
+ return;
+ _erase(p_element);
+ if (_data.size_cache==0 && _data._root)
+ _data._free_root();
+ }
+
+ bool erase(const T& p_value) {
+
+ if (!_data._root)
+ return false;
+ Element *e=find(p_value);
+ if (!e)
+ return false;
+ _erase(e);
+ if (_data.size_cache==0 && _data._root)
+ _data._free_root();
+ return true;
+ }
+
+ Element *front() const {
+
+ if (!_data._root)
+ return NULL;
+ Element *e=_data._root->left;
+ if (e==_data._nil)
+ return NULL;
+
+ while(e->left!=_data._nil)
+ e=e->left;
+
+ return e;
+ }
+
+ Element *back() const {
+
+ if (!_data._root)
+ return NULL;
+ Element *e=_data._root->left;
+ if (e==_data._nil)
+ return NULL;
+
+ while(e->right!=_data._nil)
+ e=e->right;
+
+ return e;
+ }
+
+ inline int size() const { return _data.size_cache; }
+ int calculate_depth() const {
+ // used for debug mostly
+ if (!_data._root)
+ return 0;
+ int max_d=0;
+ _calculate_depth(_data._root->left,max_d,0);
+ return max_d;
+ }
+
+ void clear() {
+
+ if (!_data._root)
+ return;
+
+ _cleanup_tree(_data._root->left);
+ _data._root->left=_data._nil;
+ _data.size_cache=0;
+ _data._nil->parent=_data._nil;
+ _data._free_root();
+ }
+
+ void operator=(const Set& p_set) {
+
+ _copy_from( p_set );
+ }
+
+ Set(const Set& p_set) {
+
+ _copy_from( p_set );
+ }
+ _FORCE_INLINE_ Set() {
+
+
+ }
+
+
+ ~Set() {
+
+ clear();
+ }
+
+};
+
+#endif