nginx源码学习2——扒、封装红黑树代码
来源:互联网 发布:初学者学化妆知乎 编辑:程序博客网 时间:2024/05/19 23:14
说明:
1.nginx红黑树除了是个通用结构体,还是定时器实现的载体,进一步学习定时器代码需要了解红黑树用法;
2.nginx红黑树基本上只提供了一个初始化红黑树、增、删节点,查找最小节点四种操作,其实对nginx也够了;
3.nginx红黑树细节暴露比较多,节点要自己malloc自己构造,插入操作的第一步(旋转前)要自己实现(尽管各种实现的不同处都只是在key相同时提供比较大小的方法),节点删除后要自己释放(当然有内存池要方便不少),树结构不要了也要自己释放;
4.因为是内部使用,没有异常检查。
综上,打算扒出来代码改点(主要是增加key比较逻辑),之后封装完全隐藏细节并构造、析构统一化,顺便加点注释,进行基本测试。本质还是要在改的过程中学习代码。
修改之后的核心代码,mytool_rbtree_raw.h
#ifndef MYTOOL_RBTREE_RAW_H #define MYTOOL_RBTREE_RAW_H namespace mytool{ typedef bool (*smallerFun)(void *,void *); struct rbtree_node_t{ unsigned key; rbtree_node_t *left; rbtree_node_t *right; rbtree_node_t *parent; unsigned char color; unsigned char data; }; struct rbtree_t{ rbtree_node_t *root; rbtree_node_t *sentinel; smallerFun sfun; };#define rbtree_init(tree, s, i) \ rbtree_sentinel_init(s); \ (tree)->root = s; \ (tree)->sentinel = s; \ (tree)->sfun = ivoid rbtree_insert(rbtree_t *tree,rbtree_node_t *node);void rbtree_delete(rbtree_t *tree,rbtree_node_t *node);//默认insert函数,已无必要//void rbtree_insert_value(rbtree_node_t *root,rbtree_node_t *node,rbtree_node_t *sentinel);//timer的insert函数,已无必要//void rbtree_insert_timer_value(rbtree_node_t *root,rbtree_node_t *node,rbtree_node_t *sentinel);//原代码对于timer对比没有相等的情况,可惜这个inline还是可能得变成函数指针inline bool timer_smaller(void *p1,void *p2){return true;}#define rbt_red(node) ((node)->color = 1)#define rbt_black(node) ((node)->color = 0)#define rbt_is_red(node) ((node)->color)#define rbt_is_black(node) (!rbt_is_red(node))#define rbt_copy_color(n1, n2) (n1->color = n2->color)#define rbtree_sentinel_init(node) rbt_black(node)static inline rbtree_node_t *rbtree_min(rbtree_node_t *node,rbtree_node_t *sentinel){ while(node->left != sentinel) node = node->left; return node;}}#endif
mytool_rbtree_raw.cpp
#include "mytool_rbtree_raw.h"#include <cstdlib> //for NULLnamespace mytool{static inline void rbtree_left_rotate(rbtree_node_t **root,rbtree_node_t *sentinel,rbtree_node_t *node);static inline void rbtree_right_rotate(rbtree_node_t **root,rbtree_node_t *sentinel,rbtree_node_t *node);void rbtree_insert(rbtree_t *tree,rbtree_node_t *node){ rbtree_node_t **root,*temp,*sentinel; /* a binary tree insert */ root = (rbtree_node_t **)&tree->root; sentinel = tree->sentinel; if(*root == sentinel){ node->parent = NULL; node->left = sentinel; node->right = sentinel; rbt_black(node); *root = node; return; } //之前的insert需要重新实现,但其实只有key相等的部分需要,其他的比如迭代过程收尾过程都是一样的,所以在此把insert函数改成了一个smallFun只比data大小的 //tree->insert(*root, node, sentinel); { rbtree_node_t **p; rbtree_node_t *temp = *root; for(;;){ if(node->key < temp->key){ p = &temp->left; }else if(node->key > temp->key){ p = &temp->right; }else if(tree->sfun(&(node->data),&(temp->data))){ p = &temp->left; }else{ p = &temp->right; } if(*p == sentinel) break; temp = *p; } *p = node; node->parent = temp; node->left = sentinel; node->right = sentinel; rbt_red(node); } /* re-balance tree */ while(node != *root && rbt_is_red(node->parent)){ if(node->parent == node->parent->parent->left){ temp = node->parent->parent->right; if(rbt_is_red(temp)){ rbt_black(node->parent); rbt_black(temp); rbt_red(node->parent->parent); node = node->parent->parent; }else{ if(node == node->parent->right){ node = node->parent; rbtree_left_rotate(root, sentinel, node); } rbt_black(node->parent); rbt_red(node->parent->parent); rbtree_right_rotate(root, sentinel, node->parent->parent); } }else{ temp = node->parent->parent->left; if(rbt_is_red(temp)){ rbt_black(node->parent); rbt_black(temp); rbt_red(node->parent->parent); node = node->parent->parent; }else{ if(node == node->parent->left){ node = node->parent; rbtree_right_rotate(root, sentinel, node); } rbt_black(node->parent); rbt_red(node->parent->parent); rbtree_left_rotate(root, sentinel, node->parent->parent); } } } rbt_black(*root);}/*void rbtree_insert_value(rbtree_node_t *temp,rbtree_node_t *node,rbtree_node_t *sentinel){ rbtree_node_t **p; for(;;){ p = (node->key < temp->key) ? &temp->left : &temp->right; if(*p == sentinel) break; temp = *p; } *p = node; node->parent = temp; node->left = sentinel; node->right = sentinel; rbt_red(node);}*/void rbtree_delete(rbtree_t *tree,rbtree_node_t *node){ unsigned red; rbtree_node_t **root,*sentinel,*subst,*temp,*w; /* a binary tree delete */ root = (rbtree_node_t **)&tree->root; sentinel = tree->sentinel; if (node->left == sentinel){ temp = node->right; subst = node; }else if(node->right == sentinel){ temp = node->left; subst = node; }else{ subst = rbtree_min(node->right, sentinel); if(subst->left != sentinel){ temp = subst->left; }else{ temp = subst->right; } } if(subst == *root){ *root = temp; rbt_black(temp); /* DEBUG stuff */ node->left = NULL; node->right = NULL; node->parent = NULL; node->key = 0; return; } red = rbt_is_red(subst); if(subst == subst->parent->left){ subst->parent->left = temp; }else{ subst->parent->right = temp; } if(subst == node){ temp->parent = subst->parent; }else{ if(subst->parent == node){ temp->parent = subst; }else{ temp->parent = subst->parent; } subst->left = node->left; subst->right = node->right; subst->parent = node->parent; rbt_copy_color(subst, node); if(node == *root){ *root = subst; }else{ if(node == node->parent->left){ node->parent->left = subst; }else{ node->parent->right = subst; } } if(subst->left != sentinel) subst->left->parent = subst; if(subst->right != sentinel) subst->right->parent = subst; } /* DEBUG stuff */ node->left = NULL; node->right = NULL; node->parent = NULL; node->key = 0; if(red) return; /* a delete fixup */ while(temp != *root && rbt_is_black(temp)){ if(temp == temp->parent->left){ w = temp->parent->right; if(rbt_is_red(w)){ rbt_black(w); rbt_red(temp->parent); rbtree_left_rotate(root,sentinel,temp->parent); w = temp->parent->right; } if(rbt_is_black(w->left) && rbt_is_black(w->right)){ rbt_red(w); temp = temp->parent; }else{ if(rbt_is_black(w->right)){ rbt_black(w->left); rbt_red(w); rbtree_right_rotate(root,sentinel,w); w = temp->parent->right; } rbt_copy_color(w,temp->parent); rbt_black(temp->parent); rbt_black(w->right); rbtree_left_rotate(root,sentinel,temp->parent); temp = *root; } }else{ w = temp->parent->left; if(rbt_is_red(w)){ rbt_black(w); rbt_red(temp->parent); rbtree_right_rotate(root,sentinel,temp->parent); w = temp->parent->left; } if(rbt_is_black(w->left) && rbt_is_black(w->right)){ rbt_red(w); temp = temp->parent; }else{ if(rbt_is_black(w->left)){ rbt_black(w->right); rbt_red(w); rbtree_left_rotate(root,sentinel,w); w = temp->parent->left; } rbt_copy_color(w, temp->parent); rbt_black(temp->parent); rbt_black(w->left); rbtree_right_rotate(root,sentinel,temp->parent); temp = *root; } } } rbt_black(temp);}static inline void rbtree_left_rotate(rbtree_node_t **root,rbtree_node_t *sentinel,rbtree_node_t *node){ rbtree_node_t *temp; temp = node->right; node->right = temp->left; if(temp->left != sentinel) temp->left->parent = node; temp->parent = node->parent; if(node == *root){ *root = temp; }else if(node == node->parent->left){ node->parent->left = temp; }else{ node->parent->right = temp; } temp->left = node; node->parent = temp;}static inline void rbtree_right_rotate(rbtree_node_t **root,rbtree_node_t *sentinel,rbtree_node_t *node){ rbtree_node_t *temp; temp = node->left; node->left = temp->right; if(temp->right != sentinel) temp->right->parent = node; temp->parent = node->parent; if(node == *root){ *root = temp; }else if(node == node->parent->right){ node->parent->right = temp; }else{ node->parent->left = temp; } temp->right = node; node->parent = temp;}}
核心代码基本测试代码:
#include "mytool_rbtree_raw.h"#include <cstring>#include <cstdio>using namespace mytool;struct person{ struct rbtree_node_t node; char namePad[30];};int main(){ struct rbtree_t rbt; struct rbtree_node_t sentinel,*prn; memset(&sentinel,sizeof(sentinel),0); rbtree_init(&rbt,&sentinel,timer_smaller); struct person n1,n2,n3,n4; n1.node.key = 11; n2.node.key = 22; n3.node.key = 33; n4.node.key = 44; strcpy((char *)(&(n1.node.data)),"once"); strcpy((char *)(&(n2.node.data)),"veintidos"); strcpy((char *)(&(n3.node.data)),"treinta y tres"); strcpy((char *)(&(n4.node.data)),"cuarenta y cuatro"); rbtree_insert(&rbt,&(n4.node)); rbtree_insert(&rbt,&(n3.node)); rbtree_insert(&rbt,&(n2.node)); rbtree_insert(&rbt,&(n1.node)); int i = 4; while(i > 0){ prn = rbtree_min(rbt.root,rbt.sentinel); printf("%dth——key:%u,name:%s\n",i,prn->key,(char *)(&(prn->data))); rbtree_delete(&rbt,prn); i--; }}
封装头文件:
mytool_rbtree.h
#ifndef MYTOOL_RBTREE_H#define MYTOOL_RBTREE_H#include <cstddef>namespace mytool{//特化的红黑树,操作只支持求最小的节点class Rbtree{ typedef bool (*smallerFun)(void *,void *); public: //fun不能为NULL //异常:out_of_memory,invalid_argument explicit Rbtree(smallerFun fun) noexcept(false) { _initPrb(fun); } //data其实可以为NULL,如果data全部为NULL就退化成了set,所以data还是不能为NULL,所以size不能为0 //为了防止数据拷贝到node内部的开销,要求使用者使用getNodeData动态获取内存,node的头结构隐藏在了返回指针的前面 //返回指针已经考虑到了对齐 //异常:out_of_memory,invalid_argument void *getNodeData(size_t size) const noexcept(false); //异常:logic_error void insertNodeData(void *data,unsigned key) const noexcept(false); //异常:invalid_argument,logic_error //每个红黑树可以增加一个全局的编号,来验证要删除的data是不是本树的,未实现,靠调用者保证 void deleteNodeData(void *data) const noexcept(false); void *getMinData() const noexcept; //删除节点一直到空,并且删除_prb ~Rbtree() noexcept; private: void _initPrb(smallerFun fun) noexcept(false); void *_prb;};}#endif
mytool_rbtree.cpp
#include "mytool_rbtree.h"#include "mytool_rbtree_raw.h"#include <stdexcept>#include <cstring>#define RBTREEP(p) ((struct rbtree_t *)(p)) #define RBTREENODEP(p) ((struct rbtree_node_t *)(p)) #define NODEMAGIC 88 #define ALIGNSIZE 16#define NODEALIGNEDSIZE ((sizeof(struct rbtree_node_t) + ALIGNSIZE - 1) & ~(ALIGNSIZE - 1))namespace mytool{ void Rbtree::_initPrb(smallerFun fun) noexcept(false){ if(fun == NULL) throw std::invalid_argument("smallerFun can not be empty"); //用new不用malloc因为new能够有分配失败策略,再失败直接抛异常 //尽管是new char,也是按照最大对齐规则的 _prb = (void *)(new char[sizeof(struct rbtree_t)]); struct rbtree_node_t *psentinel = RBTREENODEP(new char[sizeof(struct rbtree_node_t)]); rbtree_init(RBTREEP(_prb),psentinel,fun); } void *Rbtree::getNodeData(size_t size) const noexcept(false){ if(size == 0) throw std::invalid_argument("size can not be zero"); struct rbtree_node_t *prn = RBTREENODEP(new char[NODEALIGNEDSIZE + size]); memset(prn,0,NODEALIGNEDSIZE); //隐藏rbtree_node_t细节后可以加一个魔数验证传的到底是不是node的data,这里用已经没有用了的data字段 prn->data = NODEMAGIC; //color用来表示是否已经加入过node,当前合法color只有0,1 prn->color = NODEMAGIC; return (char *)prn + NODEALIGNEDSIZE; } void Rbtree::insertNodeData(void *data,unsigned key) const noexcept(false){ if(data == NULL) return; struct rbtree_node_t *prn = RBTREENODEP((char *)data - NODEALIGNEDSIZE); if(prn->data != NODEMAGIC) throw std::logic_error("data is not a valid node"); if(prn->color != NODEMAGIC) throw std::logic_error("data has been added before"); struct rbtree_t *pr = RBTREEP(_prb); prn->key = key; //底层代码没细看,说不定有坑 rbtree_insert(pr,prn); } void Rbtree::deleteNodeData(void *data) const noexcept(false){ struct rbtree_node_t *prn = RBTREENODEP((char *)data - NODEALIGNEDSIZE); if(data == NULL) return; if(prn->data != NODEMAGIC) throw std::logic_error("data is not a valid node"); struct rbtree_t *pr = RBTREEP(_prb); rbtree_delete(pr,prn); delete [] (char *)prn; } void *Rbtree::getMinData() const noexcept{ struct rbtree_t *pr = RBTREEP(_prb); if(pr->root == pr->sentinel) return NULL; struct rbtree_node_t *prn = rbtree_min(pr->root,pr->sentinel); return (char *)prn + NODEALIGNEDSIZE; } Rbtree::~Rbtree(){ void *p = getMinData(); while(p != NULL){ deleteNodeData(p); p = getMinData(); } delete [] (char *)_prb; }}
封装基本测试,testTree.cpp:
#include "mytool_rbtree.h"#include <iostream>using namespace mytool;bool smallerInt(void *p1,void *p2){ return *((int *)p1) < *((int *)p1);}int main(){ Rbtree r(smallerInt); int *p1,*p2,*p3,*p4; p1 = (int *)r.getNodeData(sizeof(int)); p2 = (int *)r.getNodeData(sizeof(int)); p3 = (int *)r.getNodeData(sizeof(int)); p4 = (int *)r.getNodeData(sizeof(int)); *p1 = 11; *p2 = 22; *p3 = 33; *p4 = 44; r.insertNodeData(p3,33); r.insertNodeData(p2,22); r.insertNodeData(p4,44); r.insertNodeData(p1,11); int *p = (int *)r.getMinData(); while(p != NULL){ std::cout<<*p<<std::endl; r.deleteNodeData(p); p = (int *)(r.getMinData()); }}
阅读全文
0 0
- nginx源码学习2——扒、封装红黑树代码
- nginx源码学习1——扒内存池代码
- Nginx学习(3)—封装的数据结构
- nginx源码学习——错误处理
- nginx源码学习——内存池
- 怎么扒JS代码?
- 神器扒网站——teleport ultra
- leveldb源码学习——系统函数封装Env
- nginx 源码学习笔记(十四)—— 全局变量ngx_cycle
- nginx源码学习——命令行选项处理
- nginx源码学习——进程间通信机制
- nginx 源码学习——处理stale event
- nginx 源码学习笔记(十四)—— 全局变量ngx_cycle
- nginx源码学习3——定时器c++实现
- nginx 源码学习笔记(二十三)—— event 模块(四) ——timer红黑树
- nginx 源码学习笔记(二十三)—— event 模块(四) ——timer红黑树
- Nginx源码分析—nginx的配置
- Nginx源码学习(2)----ngx_string
- HDU1392 Surround the Trees(凸包模版题)
- CSS权重计算问题
- python数据分析学习路线
- jmeter 保存响应到文件
- Android学习迷茫问下自己14个问题
- nginx源码学习2——扒、封装红黑树代码
- Redis主从复制和集群配置
- 深入浅出JMS(一)--JMS基本概念
- 用ajax向table插一条一条数据,使插入最新数据都在第一行
- 翻转二叉树
- Kotlin实战00---前言
- 在Ubuntu ROS中使用zsh
- redis在java中的使用(jedis)
- jdk1.7+Eclipse+Maven3.5+Hadoop2.7.3构建hadoop项目