├── LICENSE ├── Makefile ├── README └── src ├── configure.h ├── conhash.c ├── conhash.h ├── conhash_inter.c ├── conhash_inter.h ├── conhash_util.c ├── md5.c ├── md5.h ├── sample.c ├── util_rbtree.c └── util_rbtree.h /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. swordflychen@gmail.com. 3 | * All rights reserved. 4 | */ 5 | 6 | /* 7 | * Copyright (C) 2010. sparkling.liang@hotmail.com. 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR 23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | */ 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # output path 3 | BIN = ./bin 4 | SRC = ./src 5 | 6 | # debug stuff 7 | ifeq ($(CFLAG), DEBUG) 8 | CFLAGS += -g 9 | endif 10 | 11 | AR = ar -cqs 12 | # itermidiate objects 13 | OBJ = $(addprefix $(BIN)/, \ 14 | md5.o \ 15 | util_rbtree.o \ 16 | conhash_inter.o \ 17 | conhash_util.o \ 18 | conhash.o \ 19 | ) 20 | 21 | SAMPLE_OBJS = $(addprefix $(BIN)/, \ 22 | sample.o \ 23 | ) 24 | 25 | # include file path 26 | INC = -I$(SRC) 27 | 28 | TARGETS = $(BIN)/libconhash.a $(BIN)/sample 29 | 30 | all: clean prepare $(TARGETS) 31 | 32 | # build libconhash as a static lib 33 | $(BIN)/libconhash.a: $(OBJ) 34 | $(AR) $@ $(OBJ) 35 | 36 | # build sample 37 | $(BIN)/sample: $(SAMPLE_OBJS) 38 | gcc -O -o $@ $(SAMPLE_OBJS) -L. -L$(BIN) -lconhash 39 | 40 | 41 | $(BIN)/%.o: $(SRC)/%.c 42 | gcc $(INC) $(CFLAGS) -c $< -o $@ 43 | 44 | # prepare the bin dir 45 | prepare: 46 | -mkdir $(BIN) 47 | 48 | clean: 49 | -rm -rf $(BIN) 50 | 51 | .PHONY: all prepare clean 52 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | What is libconhash? 3 | libconhash is a consistent hashing library, which can be compiled both on Windows and Linux platform, with the following features: 4 | 5 | 1. High performance and easy to use, libconhash uses a red-black tree to manange all nodes to achieve high performance. 6 | 2. By default it uses MD5 algorithm, but it also supports user-defined hash function. 7 | 3. Easy to scale according to node's processing capacity. 8 | 9 | -------------------------------------------------------------------------------------- 10 | To build libconhash 11 | on Linux using 12 | make 13 | to build a debug version, using 14 | make CFLAG=DEBUG 15 | on Windows there are win32 projects, just build them 16 | 17 | -------------------------------------------------------------------------------------- 18 | To use libconhash 19 | Include headers libconhash.h and configure.h, and link the conhash binary library file. 20 | There is a sample in the project shows how to use the library. 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/configure.h: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright (C) 2010. sparkling.liang@hotmail.com. All rights reserved. */ 3 | 4 | #ifndef __CONFIGURE_H_ 5 | #define __CONFIGURE_H_ 6 | 7 | 8 | typedef unsigned int u_int; 9 | typedef unsigned char u_char; 10 | typedef long util_long; 11 | 12 | #endif /* end __CONFIGURE_H_ */ 13 | -------------------------------------------------------------------------------- /src/conhash.c: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright (C) 2010. sparkling.liang@hotmail.com. All rights reserved. */ 3 | 4 | #include "conhash.h" 5 | #include "conhash_inter.h" 6 | 7 | struct conhash_s* conhash_init(conhash_cb_hashfunc pfhash) 8 | { 9 | /* alloc memory and set to zero */ 10 | struct conhash_s *conhash = (struct conhash_s*)calloc(1, sizeof(struct conhash_s)); 11 | if(conhash == NULL) 12 | { 13 | return NULL; 14 | } 15 | do 16 | { 17 | /* setup callback functions */ 18 | if(pfhash != NULL) 19 | { 20 | conhash->cb_hashfunc = pfhash; 21 | } 22 | else 23 | { 24 | conhash->cb_hashfunc = __conhash_hash_def; 25 | } 26 | util_rbtree_init(&conhash->vnode_tree); 27 | return conhash; 28 | 29 | }while(0); 30 | 31 | free(conhash); 32 | return NULL; 33 | } 34 | 35 | void conhash_fini(struct conhash_s *conhash) 36 | { 37 | if(conhash != NULL) 38 | { 39 | /* free rb tree */ 40 | while(!util_rbtree_isempty(&(conhash->vnode_tree))) 41 | { 42 | util_rbtree_node_t *rbnode = conhash->vnode_tree.root; 43 | util_rbtree_delete(&(conhash->vnode_tree), rbnode); 44 | __conhash_del_rbnode(rbnode); 45 | } 46 | free(conhash); 47 | } 48 | } 49 | 50 | void conhash_set_node(struct node_s *node, const char *iden, u_int replica) 51 | { 52 | strncpy(node->iden, iden, sizeof(node->iden)-1); 53 | node->replicas = replica; 54 | node->flag = NODE_FLAG_INIT; 55 | } 56 | 57 | int conhash_add_node(struct conhash_s *conhash, struct node_s *node) 58 | { 59 | if((conhash==NULL) || (node==NULL)) 60 | { 61 | return -1; 62 | } 63 | /* check node fisrt */ 64 | if(!(node->flag&NODE_FLAG_INIT) || (node->flag&NODE_FLAG_IN)) 65 | { 66 | return -1; 67 | } 68 | node->flag |= NODE_FLAG_IN; 69 | /* add replicas of server */ 70 | __conhash_add_replicas(conhash, node); 71 | 72 | return 0; 73 | } 74 | 75 | int conhash_del_node(struct conhash_s *conhash, struct node_s *node) 76 | { 77 | if((conhash==NULL) || (node==NULL)) 78 | { 79 | return -1; 80 | } 81 | /* check node first */ 82 | if(!(node->flag&NODE_FLAG_INIT) || !(node->flag&NODE_FLAG_IN)) 83 | { 84 | return -1; 85 | } 86 | node->flag &= (~NODE_FLAG_IN); 87 | /* add replicas of server */ 88 | __conhash_del_replicas(conhash, node); 89 | 90 | return 0; 91 | } 92 | 93 | const struct node_s* conhash_lookup(const struct conhash_s *conhash, const char *object) 94 | { 95 | long hash; 96 | const util_rbtree_node_t *rbnode; 97 | if((conhash==NULL) || (conhash->ivnodes==0) || (object==NULL)) 98 | { 99 | return NULL; 100 | } 101 | /* calc hash value */ 102 | hash = conhash->cb_hashfunc(object); 103 | 104 | rbnode = util_rbtree_lookup(&(conhash->vnode_tree), hash); 105 | if(rbnode != NULL) 106 | { 107 | struct virtual_node_s *vnode = rbnode->data; 108 | return vnode->node; 109 | } 110 | return NULL; 111 | } 112 | -------------------------------------------------------------------------------- /src/conhash.h: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright (C) 2010. sparkling.liang@hotmail.com. All rights reserved. */ 3 | 4 | #ifndef __CON_HASH_H_ 5 | #define __CON_HASH_H_ 6 | 7 | #include "configure.h" 8 | #include 9 | 10 | #ifdef CONHASH_EXPORTS 11 | 12 | /* windows platform DLL */ 13 | #if (defined (WIN32) || defined (__WIN32)) && (defined _USRDLL) 14 | #define CONHASH_API __declspec(dllexport) 15 | #else 16 | #define CONHASH_API __declspec(dllimport) 17 | #endif 18 | 19 | #else /* Linux, or static lib */ 20 | #define CONHASH_API 21 | #endif 22 | 23 | #define NODE_FLAG_INIT 0x01 /* node is initialized */ 24 | #define NODE_FLAG_IN 0x02 /* node is added in the server */ 25 | 26 | /* nodes structure */ 27 | struct node_s 28 | { 29 | char iden[64]; /* node name or some thing identifies the node */ 30 | u_int replicas; /* number of replica virtual nodes */ 31 | u_int flag; 32 | }; 33 | 34 | /* 35 | * callback function to calculate hash value 36 | * @instr: input string 37 | */ 38 | typedef long (*conhash_cb_hashfunc)(const char *instr); 39 | 40 | struct conhash_s; 41 | 42 | /* export interfaces */ 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | /* initialize conhash library 47 | * @pfhash : hash function, NULL to use default MD5 method 48 | * return a conhash_s instance 49 | */ 50 | CONHASH_API struct conhash_s* conhash_init(conhash_cb_hashfunc pfhash); 51 | 52 | /* finalize lib */ 53 | CONHASH_API void conhash_fini(struct conhash_s *conhash); 54 | 55 | /* set node */ 56 | CONHASH_API void conhash_set_node(struct node_s *node, const char *iden, u_int replica); 57 | 58 | /* 59 | * add a new node 60 | * @node: the node to add 61 | */ 62 | CONHASH_API int conhash_add_node(struct conhash_s *conhash, struct node_s *node); 63 | 64 | /* remove a node */ 65 | CONHASH_API int conhash_del_node(struct conhash_s *conhash, struct node_s *node); 66 | 67 | /* 68 | * update a node's virtual nodes 69 | * @replica: new replica of server 70 | * return 0 success, -1 failed 71 | */ 72 | CONHASH_API int conhash_update_node(struct conhash_s *conhash, struct node_s *node, u_int replica); 73 | 74 | /* 75 | * lookup a server which object belongs to 76 | * @object: the input string which indicates an object 77 | * return the server_s structure, do not modify the value, or it will cause a disaster 78 | */ 79 | CONHASH_API const struct node_s* conhash_lookup(const struct conhash_s *conhash, const char *object); 80 | 81 | /* some utility functions export*/ 82 | CONHASH_API void conhash_md5_digest(const u_char *instr, u_char digest[16]); 83 | /* get virtual node number in the hash */ 84 | CONHASH_API u_int conhash_get_vnodes_num(const struct conhash_s *conhash); 85 | /* 86 | * get virtual nodes in ascending oder 87 | * @values, pointer to an array, stores all the nodes's hash value 88 | * @size, how many nodes to get, can't be less than the array size 89 | */ 90 | CONHASH_API void conhash_get_vnodes(const struct conhash_s *conhash, long *values, int size); 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif 95 | 96 | #endif /* end __CON_HASH_H_ */ 97 | -------------------------------------------------------------------------------- /src/conhash_inter.c: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright (C) 2010. sparkling.liang@hotmail.com. All rights reserved. */ 3 | 4 | #include "conhash_inter.h" 5 | #include "conhash.h" 6 | 7 | /* 8 | * the default hash function, using md5 algorithm 9 | * @instr: input string 10 | */ 11 | long __conhash_hash_def(const char *instr) 12 | { 13 | int i; 14 | long hash = 0; 15 | unsigned char digest[16]; 16 | conhash_md5_digest((const u_char*)instr, digest); 17 | 18 | /* use successive 4-bytes from hash as numbers */ 19 | for(i = 0; i < 4; i++) 20 | { 21 | hash += ((long)(digest[i*4 + 3]&0xFF) << 24) 22 | | ((long)(digest[i*4 + 2]&0xFF) << 16) 23 | | ((long)(digest[i*4 + 1]&0xFF) << 8) 24 | | ((long)(digest[i*4 + 0]&0xFF)); 25 | } 26 | return hash; 27 | } 28 | 29 | void __conhash_node2string(const struct node_s *node, u_int replica_idx, char buf[128], u_int *len) 30 | { 31 | #if (defined (WIN32) || defined (__WIN32)) 32 | _snprintf_s(buf, 127, _TRUNCATE, "%s-%03d", node->iden, replica_idx); 33 | #else 34 | snprintf(buf, 127, "%s-%03d", node->iden, replica_idx); 35 | #endif 36 | } 37 | 38 | void __conhash_add_replicas(struct conhash_s *conhash, struct node_s *node) 39 | { 40 | u_int i, len; 41 | long hash; 42 | char buff[128]; 43 | util_rbtree_node_t *rbnode; 44 | for(i = 0; i < node->replicas; i++) 45 | { 46 | /* calc hash value of all virtual nodes */ 47 | __conhash_node2string(node, i, buff, &len); 48 | hash = conhash->cb_hashfunc(buff); 49 | /* add virtual node, check duplication */ 50 | if(util_rbtree_search(&(conhash->vnode_tree), hash) == NULL) 51 | { 52 | rbnode = __conhash_get_rbnode(node, hash); 53 | if(rbnode != NULL) 54 | { 55 | util_rbtree_insert(&(conhash->vnode_tree), rbnode); 56 | conhash->ivnodes++; 57 | } 58 | } 59 | } 60 | } 61 | 62 | void __conhash_del_replicas(struct conhash_s *conhash, struct node_s *node) 63 | { 64 | u_int i, len; 65 | long hash; 66 | char buff[128]; 67 | struct virtual_node_s *vnode; 68 | util_rbtree_node_t *rbnode; 69 | for(i = 0; i < node->replicas; i++) 70 | { 71 | /* calc hash value of all virtual nodes */ 72 | __conhash_node2string(node, i, buff, &len); 73 | hash = conhash->cb_hashfunc(buff); 74 | rbnode = util_rbtree_search(&(conhash->vnode_tree), hash); 75 | if(rbnode != NULL) 76 | { 77 | vnode = rbnode->data; 78 | if((vnode->hash == hash) && (vnode->node == node)) 79 | { 80 | conhash->ivnodes--; 81 | util_rbtree_delete(&(conhash->vnode_tree), rbnode); 82 | __conhash_del_rbnode(rbnode); 83 | } 84 | } 85 | } 86 | } 87 | 88 | util_rbtree_node_t *__conhash_get_rbnode(struct node_s *node, long hash) 89 | { 90 | util_rbtree_node_t *rbnode; 91 | rbnode = (util_rbtree_node_t *)malloc(sizeof(util_rbtree_node_t)); 92 | if(rbnode != NULL) 93 | { 94 | rbnode->key = hash; 95 | rbnode->data = malloc(sizeof(struct virtual_node_s)); 96 | if(rbnode->data != NULL) 97 | { 98 | struct virtual_node_s *vnode = rbnode->data; 99 | vnode->hash = hash; 100 | vnode->node = node; 101 | } 102 | else 103 | { 104 | free(rbnode); 105 | rbnode = NULL; 106 | } 107 | } 108 | return rbnode; 109 | } 110 | 111 | void __conhash_del_rbnode(util_rbtree_node_t *rbnode) 112 | { 113 | struct virtual_node_s *node; 114 | node = rbnode->data; 115 | free(node); 116 | free(rbnode); 117 | } 118 | -------------------------------------------------------------------------------- /src/conhash_inter.h: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright (C) 2010. sparkling.liang@hotmail.com. All rights reserved. */ 3 | 4 | #ifndef __CONHASH_INTER_H_ 5 | #define __CONHASH_INTER_H_ 6 | 7 | #include "configure.h" 8 | #include "md5.h" 9 | #include "util_rbtree.h" 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /* virtual node structure */ 18 | struct virtual_node_s 19 | { 20 | long hash; 21 | struct node_s *node; /* pointer to node */ 22 | }; 23 | 24 | /* consistent hashing */ 25 | struct conhash_s 26 | { 27 | util_rbtree_t vnode_tree; /* rbtree of virtual nodes */ 28 | u_int ivnodes; /* virtual node number */ 29 | long (*cb_hashfunc)(const char *); 30 | }; 31 | 32 | struct __get_vnodes_s 33 | { 34 | long *values; 35 | long size, cur; 36 | }; 37 | 38 | 39 | int __conhash_vnode_cmp(const void *v1, const void *v2); 40 | 41 | void __conhash_node2string(const struct node_s *node, u_int replica_idx, char buf[128], u_int *len); 42 | long __conhash_hash_def(const char *instr); 43 | void __conhash_add_replicas(struct conhash_s *conhash, struct node_s *node); 44 | void __conhash_del_replicas(struct conhash_s *conhash, struct node_s *node); 45 | 46 | util_rbtree_node_t *__conhash_get_rbnode(struct node_s *node, long hash); 47 | void __conhash_del_rbnode(util_rbtree_node_t *rbnode); 48 | 49 | #endif /* end __CONHASH_INTER_H_ */ 50 | -------------------------------------------------------------------------------- /src/conhash_util.c: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright (C) 2010. sparkling.liang@hotmail.com. All rights reserved. */ 3 | 4 | #include "conhash.h" 5 | #include "conhash_inter.h" 6 | 7 | 8 | void conhash_md5_digest(const u_char *instr, u_char digest[16]) 9 | { 10 | md5_state_t md5state; 11 | 12 | md5_init(&md5state); 13 | md5_append(&md5state, instr, strlen(instr)); 14 | md5_finish(&md5state, digest); 15 | } 16 | 17 | static void __get_vnodes(util_rbtree_node_t *node, void *data) 18 | { 19 | struct __get_vnodes_s *vnodes = (struct __get_vnodes_s *)data; 20 | if(vnodes->cur < vnodes->size) 21 | { 22 | vnodes->values[vnodes->cur++] = node->key; 23 | } 24 | } 25 | void conhash_get_vnodes(const struct conhash_s *conhash, long *values, int size) 26 | { 27 | struct __get_vnodes_s vnodes; 28 | if((conhash==NULL) || (values==NULL) || (size<=0)) 29 | { 30 | return; 31 | } 32 | vnodes.values = values; 33 | vnodes.size = size; 34 | vnodes.cur = 0; 35 | util_rbtree_mid_travel(&(conhash->vnode_tree), __get_vnodes, &vnodes); 36 | } 37 | 38 | u_int conhash_get_vnodes_num(const struct conhash_s *conhash) 39 | { 40 | if(conhash == NULL) 41 | { 42 | return 0; 43 | } 44 | return conhash->ivnodes; 45 | } 46 | -------------------------------------------------------------------------------- /src/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | 20 | L. Peter Deutsch 21 | ghost@aladdin.com 22 | 23 | */ 24 | /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ 25 | /* 26 | Independent implementation of MD5 (RFC 1321). 27 | 28 | This code implements the MD5 Algorithm defined in RFC 1321, whose 29 | text is available at 30 | http://www.ietf.org/rfc/rfc1321.txt 31 | The code is derived from the text of the RFC, including the test suite 32 | (section A.5) but excluding the rest of Appendix A. It does not include 33 | any code or documentation that is identified in the RFC as being 34 | copyrighted. 35 | 36 | The original and principal author of md5.c is L. Peter Deutsch 37 | . Other authors are noted in the change history 38 | that follows (in reverse chronological order): 39 | 40 | 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order 41 | either statically or dynamically; added missing #include 42 | in library. 43 | 2002-03-11 lpd Corrected argument list for main(), and added int return 44 | type, in test program and T value program. 45 | 2002-02-21 lpd Added missing #include in test program. 46 | 2000-07-03 lpd Patched to eliminate warnings about "constant is 47 | unsigned in ANSI C, signed in traditional"; made test program 48 | self-checking. 49 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 50 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 51 | 1999-05-03 lpd Original version. 52 | */ 53 | 54 | #include "md5.h" 55 | #include 56 | 57 | #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ 58 | #ifdef ARCH_IS_BIG_ENDIAN 59 | # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) 60 | #else 61 | # define BYTE_ORDER 0 62 | #endif 63 | 64 | #define T_MASK ((md5_word_t)~0) 65 | #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) 66 | #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) 67 | #define T3 0x242070db 68 | #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) 69 | #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) 70 | #define T6 0x4787c62a 71 | #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) 72 | #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) 73 | #define T9 0x698098d8 74 | #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) 75 | #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) 76 | #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) 77 | #define T13 0x6b901122 78 | #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) 79 | #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) 80 | #define T16 0x49b40821 81 | #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) 82 | #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) 83 | #define T19 0x265e5a51 84 | #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) 85 | #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) 86 | #define T22 0x02441453 87 | #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) 88 | #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) 89 | #define T25 0x21e1cde6 90 | #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) 91 | #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) 92 | #define T28 0x455a14ed 93 | #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) 94 | #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) 95 | #define T31 0x676f02d9 96 | #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) 97 | #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) 98 | #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) 99 | #define T35 0x6d9d6122 100 | #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) 101 | #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) 102 | #define T38 0x4bdecfa9 103 | #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) 104 | #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) 105 | #define T41 0x289b7ec6 106 | #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) 107 | #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) 108 | #define T44 0x04881d05 109 | #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) 110 | #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) 111 | #define T47 0x1fa27cf8 112 | #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) 113 | #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) 114 | #define T50 0x432aff97 115 | #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) 116 | #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) 117 | #define T53 0x655b59c3 118 | #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) 119 | #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) 120 | #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) 121 | #define T57 0x6fa87e4f 122 | #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) 123 | #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) 124 | #define T60 0x4e0811a1 125 | #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) 126 | #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) 127 | #define T63 0x2ad7d2bb 128 | #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) 129 | 130 | 131 | static void 132 | md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) 133 | { 134 | md5_word_t 135 | a = pms->abcd[0], b = pms->abcd[1], 136 | c = pms->abcd[2], d = pms->abcd[3]; 137 | md5_word_t t; 138 | #if BYTE_ORDER > 0 139 | /* Define storage only for big-endian CPUs. */ 140 | md5_word_t X[16]; 141 | #else 142 | /* Define storage for little-endian or both types of CPUs. */ 143 | md5_word_t xbuf[16]; 144 | const md5_word_t *X; 145 | #endif 146 | 147 | { 148 | #if BYTE_ORDER == 0 149 | /* 150 | * Determine dynamically whether this is a big-endian or 151 | * little-endian machine, since we can use a more efficient 152 | * algorithm on the latter. 153 | */ 154 | static const int w = 1; 155 | 156 | if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ 157 | #endif 158 | #if BYTE_ORDER <= 0 /* little-endian */ 159 | { 160 | /* 161 | * On little-endian machines, we can process properly aligned 162 | * data without copying it. 163 | */ 164 | if (!((data - (const md5_byte_t *)0) & 3)) { 165 | /* data are properly aligned */ 166 | X = (const md5_word_t *)data; 167 | } else { 168 | /* not aligned */ 169 | memcpy(xbuf, data, 64); 170 | X = xbuf; 171 | } 172 | } 173 | #endif 174 | #if BYTE_ORDER == 0 175 | else /* dynamic big-endian */ 176 | #endif 177 | #if BYTE_ORDER >= 0 /* big-endian */ 178 | { 179 | /* 180 | * On big-endian machines, we must arrange the bytes in the 181 | * right order. 182 | */ 183 | const md5_byte_t *xp = data; 184 | int i; 185 | 186 | # if BYTE_ORDER == 0 187 | X = xbuf; /* (dynamic only) */ 188 | # else 189 | # define xbuf X /* (static only) */ 190 | # endif 191 | for (i = 0; i < 16; ++i, xp += 4) 192 | xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); 193 | } 194 | #endif 195 | } 196 | 197 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) 198 | 199 | /* Round 1. */ 200 | /* Let [abcd k s i] denote the operation 201 | a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ 202 | #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) 203 | #define SET(a, b, c, d, k, s, Ti)\ 204 | t = a + F(b,c,d) + X[k] + Ti;\ 205 | a = ROTATE_LEFT(t, s) + b 206 | /* Do the following 16 operations. */ 207 | SET(a, b, c, d, 0, 7, T1); 208 | SET(d, a, b, c, 1, 12, T2); 209 | SET(c, d, a, b, 2, 17, T3); 210 | SET(b, c, d, a, 3, 22, T4); 211 | SET(a, b, c, d, 4, 7, T5); 212 | SET(d, a, b, c, 5, 12, T6); 213 | SET(c, d, a, b, 6, 17, T7); 214 | SET(b, c, d, a, 7, 22, T8); 215 | SET(a, b, c, d, 8, 7, T9); 216 | SET(d, a, b, c, 9, 12, T10); 217 | SET(c, d, a, b, 10, 17, T11); 218 | SET(b, c, d, a, 11, 22, T12); 219 | SET(a, b, c, d, 12, 7, T13); 220 | SET(d, a, b, c, 13, 12, T14); 221 | SET(c, d, a, b, 14, 17, T15); 222 | SET(b, c, d, a, 15, 22, T16); 223 | #undef SET 224 | 225 | /* Round 2. */ 226 | /* Let [abcd k s i] denote the operation 227 | a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ 228 | #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) 229 | #define SET(a, b, c, d, k, s, Ti)\ 230 | t = a + G(b,c,d) + X[k] + Ti;\ 231 | a = ROTATE_LEFT(t, s) + b 232 | /* Do the following 16 operations. */ 233 | SET(a, b, c, d, 1, 5, T17); 234 | SET(d, a, b, c, 6, 9, T18); 235 | SET(c, d, a, b, 11, 14, T19); 236 | SET(b, c, d, a, 0, 20, T20); 237 | SET(a, b, c, d, 5, 5, T21); 238 | SET(d, a, b, c, 10, 9, T22); 239 | SET(c, d, a, b, 15, 14, T23); 240 | SET(b, c, d, a, 4, 20, T24); 241 | SET(a, b, c, d, 9, 5, T25); 242 | SET(d, a, b, c, 14, 9, T26); 243 | SET(c, d, a, b, 3, 14, T27); 244 | SET(b, c, d, a, 8, 20, T28); 245 | SET(a, b, c, d, 13, 5, T29); 246 | SET(d, a, b, c, 2, 9, T30); 247 | SET(c, d, a, b, 7, 14, T31); 248 | SET(b, c, d, a, 12, 20, T32); 249 | #undef SET 250 | 251 | /* Round 3. */ 252 | /* Let [abcd k s t] denote the operation 253 | a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ 254 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 255 | #define SET(a, b, c, d, k, s, Ti)\ 256 | t = a + H(b,c,d) + X[k] + Ti;\ 257 | a = ROTATE_LEFT(t, s) + b 258 | /* Do the following 16 operations. */ 259 | SET(a, b, c, d, 5, 4, T33); 260 | SET(d, a, b, c, 8, 11, T34); 261 | SET(c, d, a, b, 11, 16, T35); 262 | SET(b, c, d, a, 14, 23, T36); 263 | SET(a, b, c, d, 1, 4, T37); 264 | SET(d, a, b, c, 4, 11, T38); 265 | SET(c, d, a, b, 7, 16, T39); 266 | SET(b, c, d, a, 10, 23, T40); 267 | SET(a, b, c, d, 13, 4, T41); 268 | SET(d, a, b, c, 0, 11, T42); 269 | SET(c, d, a, b, 3, 16, T43); 270 | SET(b, c, d, a, 6, 23, T44); 271 | SET(a, b, c, d, 9, 4, T45); 272 | SET(d, a, b, c, 12, 11, T46); 273 | SET(c, d, a, b, 15, 16, T47); 274 | SET(b, c, d, a, 2, 23, T48); 275 | #undef SET 276 | 277 | /* Round 4. */ 278 | /* Let [abcd k s t] denote the operation 279 | a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ 280 | #define I(x, y, z) ((y) ^ ((x) | ~(z))) 281 | #define SET(a, b, c, d, k, s, Ti)\ 282 | t = a + I(b,c,d) + X[k] + Ti;\ 283 | a = ROTATE_LEFT(t, s) + b 284 | /* Do the following 16 operations. */ 285 | SET(a, b, c, d, 0, 6, T49); 286 | SET(d, a, b, c, 7, 10, T50); 287 | SET(c, d, a, b, 14, 15, T51); 288 | SET(b, c, d, a, 5, 21, T52); 289 | SET(a, b, c, d, 12, 6, T53); 290 | SET(d, a, b, c, 3, 10, T54); 291 | SET(c, d, a, b, 10, 15, T55); 292 | SET(b, c, d, a, 1, 21, T56); 293 | SET(a, b, c, d, 8, 6, T57); 294 | SET(d, a, b, c, 15, 10, T58); 295 | SET(c, d, a, b, 6, 15, T59); 296 | SET(b, c, d, a, 13, 21, T60); 297 | SET(a, b, c, d, 4, 6, T61); 298 | SET(d, a, b, c, 11, 10, T62); 299 | SET(c, d, a, b, 2, 15, T63); 300 | SET(b, c, d, a, 9, 21, T64); 301 | #undef SET 302 | 303 | /* Then perform the following additions. (That is increment each 304 | of the four registers by the value it had before this block 305 | was started.) */ 306 | pms->abcd[0] += a; 307 | pms->abcd[1] += b; 308 | pms->abcd[2] += c; 309 | pms->abcd[3] += d; 310 | } 311 | 312 | void 313 | md5_init(md5_state_t *pms) 314 | { 315 | pms->count[0] = pms->count[1] = 0; 316 | pms->abcd[0] = 0x67452301; 317 | pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; 318 | pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; 319 | pms->abcd[3] = 0x10325476; 320 | } 321 | 322 | void 323 | md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) 324 | { 325 | const md5_byte_t *p = data; 326 | int left = nbytes; 327 | int offset = (pms->count[0] >> 3) & 63; 328 | md5_word_t nbits = (md5_word_t)(nbytes << 3); 329 | 330 | if (nbytes <= 0) 331 | return; 332 | 333 | /* Update the message length. */ 334 | pms->count[1] += nbytes >> 29; 335 | pms->count[0] += nbits; 336 | if (pms->count[0] < nbits) 337 | pms->count[1]++; 338 | 339 | /* Process an initial partial block. */ 340 | if (offset) { 341 | int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); 342 | 343 | memcpy(pms->buf + offset, p, copy); 344 | if (offset + copy < 64) 345 | return; 346 | p += copy; 347 | left -= copy; 348 | md5_process(pms, pms->buf); 349 | } 350 | 351 | /* Process full blocks. */ 352 | for (; left >= 64; p += 64, left -= 64) 353 | md5_process(pms, p); 354 | 355 | /* Process a final partial block. */ 356 | if (left) 357 | memcpy(pms->buf, p, left); 358 | } 359 | 360 | void 361 | md5_finish(md5_state_t *pms, md5_byte_t digest[16]) 362 | { 363 | static const md5_byte_t pad[64] = { 364 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 365 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 366 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 368 | }; 369 | md5_byte_t data[8]; 370 | int i; 371 | 372 | /* Save the length before padding. */ 373 | for (i = 0; i < 8; ++i) 374 | data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); 375 | /* Pad to 56 bytes mod 64. */ 376 | md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); 377 | /* Append the length. */ 378 | md5_append(pms, data, 8); 379 | for (i = 0; i < 16; ++i) 380 | digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); 381 | } 382 | -------------------------------------------------------------------------------- /src/md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | 20 | L. Peter Deutsch 21 | ghost@aladdin.com 22 | 23 | */ 24 | /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ 25 | /* 26 | Independent implementation of MD5 (RFC 1321). 27 | 28 | This code implements the MD5 Algorithm defined in RFC 1321, whose 29 | text is available at 30 | http://www.ietf.org/rfc/rfc1321.txt 31 | The code is derived from the text of the RFC, including the test suite 32 | (section A.5) but excluding the rest of Appendix A. It does not include 33 | any code or documentation that is identified in the RFC as being 34 | copyrighted. 35 | 36 | The original and principal author of md5.h is L. Peter Deutsch 37 | . Other authors are noted in the change history 38 | that follows (in reverse chronological order): 39 | 40 | 2002-04-13 lpd Removed support for non-ANSI compilers; removed 41 | references to Ghostscript; clarified derivation from RFC 1321; 42 | now handles byte order either statically or dynamically. 43 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 44 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); 45 | added conditionalization for C++ compilation from Martin 46 | Purschke . 47 | 1999-05-03 lpd Original version. 48 | */ 49 | 50 | #ifndef md5_INCLUDED 51 | # define md5_INCLUDED 52 | 53 | /* 54 | * This package supports both compile-time and run-time determination of CPU 55 | * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be 56 | * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is 57 | * defined as non-zero, the code will be compiled to run only on big-endian 58 | * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to 59 | * run on either big- or little-endian CPUs, but will run slightly less 60 | * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. 61 | */ 62 | 63 | typedef unsigned char md5_byte_t; /* 8-bit byte */ 64 | typedef unsigned int md5_word_t; /* 32-bit word */ 65 | 66 | /* Define the state of the MD5 Algorithm. */ 67 | typedef struct md5_state_s { 68 | md5_word_t count[2]; /* message length in bits, lsw first */ 69 | md5_word_t abcd[4]; /* digest buffer */ 70 | md5_byte_t buf[64]; /* accumulate block */ 71 | } md5_state_t; 72 | 73 | #ifdef __cplusplus 74 | extern "C" 75 | { 76 | #endif 77 | 78 | /* Initialize the algorithm. */ 79 | 80 | #ifdef WIN32 81 | _declspec(dllexport) 82 | #endif 83 | void md5_init(md5_state_t *pms); 84 | 85 | /* Append a string to the message. */ 86 | #ifdef WIN32 87 | _declspec(dllexport) 88 | #endif 89 | void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); 90 | 91 | /* Finish the message and return the digest. */ 92 | #ifdef WIN32 93 | _declspec(dllexport) 94 | #endif 95 | void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); 96 | 97 | #ifdef __cplusplus 98 | } /* end extern "C" */ 99 | #endif 100 | 101 | #endif /* md5_INCLUDED */ 102 | -------------------------------------------------------------------------------- /src/sample.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | 6 | #include "conhash.h" 7 | 8 | struct node_s g_nodes[64]; 9 | int main() 10 | { 11 | int i; 12 | const struct node_s *node; 13 | char str[128]; 14 | long hashes[512]; 15 | 16 | /* init conhash instance */ 17 | struct conhash_s *conhash = conhash_init(NULL); 18 | if(conhash) 19 | { 20 | /* set nodes */ 21 | conhash_set_node(&g_nodes[0], "titanic", 32); 22 | conhash_set_node(&g_nodes[1], "terminator2018", 24); 23 | conhash_set_node(&g_nodes[2], "Xenomorph", 25); 24 | conhash_set_node(&g_nodes[3], "True Lies", 10); 25 | conhash_set_node(&g_nodes[4], "avantar", 48); 26 | 27 | /* add nodes */ 28 | conhash_add_node(conhash, &g_nodes[0]); 29 | conhash_add_node(conhash, &g_nodes[1]); 30 | conhash_add_node(conhash, &g_nodes[2]); 31 | conhash_add_node(conhash, &g_nodes[3]); 32 | conhash_add_node(conhash, &g_nodes[4]); 33 | 34 | printf("virtual nodes number %d\n", conhash_get_vnodes_num(conhash)); 35 | printf("the hashing results--------------------------------------:\n"); 36 | 37 | /* try object */ 38 | for(i = 0; i < 20; i++) 39 | { 40 | sprintf(str, "James.km%03d", i); 41 | node = conhash_lookup(conhash, str); 42 | if(node) printf("[%16s] is in node: [%16s]\n", str, node->iden); 43 | } 44 | conhash_get_vnodes(conhash, hashes, sizeof(hashes)/sizeof(hashes[0])); 45 | conhash_del_node(conhash, &g_nodes[2]); 46 | printf("remove node[%s], virtual nodes number %d\n", g_nodes[2].iden, conhash_get_vnodes_num(conhash)); 47 | printf("the hashing results--------------------------------------:\n"); 48 | for(i = 0; i < 20; i++) 49 | { 50 | sprintf(str, "James.km%03d", i); 51 | node = conhash_lookup(conhash, str); 52 | if(node) printf("[%16s] is in node: [%16s]\n", str, node->iden); 53 | } 54 | } 55 | conhash_fini(conhash); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /src/util_rbtree.c: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright (C) 2010. sparkling.liang@hotmail.com. All rights reserved. */ 3 | 4 | #include "util_rbtree.h" 5 | 6 | /* the NULL node of tree */ 7 | #define _NULL(rbtree) (&((rbtree)->null)) 8 | 9 | /* structures used to check a rb tree */ 10 | struct rbtree_check_s 11 | { 12 | short rbh; /* rb height of the tree */ 13 | short maxd; /* max depth of the tree */ 14 | int fini; /* check failed ? */ 15 | const util_rbtree_node_t *null; /* sentinel of the tree */ 16 | }; 17 | 18 | typedef struct rbtree_check_s rbtree_check_t; 19 | 20 | static void rbtree_insert_fixup(util_rbtree_t *rbtree, util_rbtree_node_t *node); 21 | static void rbtree_delete_fixup(util_rbtree_t *rbtree, util_rbtree_node_t *node); 22 | static void rbtree_left_rotate(util_rbtree_t *rbtree, util_rbtree_node_t *node); 23 | static void rbtree_right_rotate(util_rbtree_t *rbtree, util_rbtree_node_t *node); 24 | 25 | void util_rbtree_init(util_rbtree_t *rbtree) 26 | { 27 | if(rbtree != NULL) 28 | { 29 | util_rbt_black(_NULL(rbtree)); /* null MUST be black */ 30 | rbtree->root = _NULL(rbtree); 31 | rbtree->size = 0; 32 | } 33 | } 34 | 35 | util_rbtree_node_t* util_rbsubtree_min(util_rbtree_node_t *node, util_rbtree_node_t *sentinel) 36 | { 37 | if(node == sentinel) return NULL; 38 | while(node->left != sentinel) node = node->left; 39 | return node; 40 | } 41 | 42 | util_rbtree_node_t* util_rbsubtree_max(util_rbtree_node_t *node, util_rbtree_node_t *sentinel) 43 | { 44 | if(node == sentinel) return NULL; 45 | while(node->right != sentinel) node = node->right; 46 | return node; 47 | } 48 | 49 | void util_rbtree_insert(util_rbtree_t *rbtree, util_rbtree_node_t *node) 50 | { 51 | util_rbtree_node_t *x, *y; 52 | if((rbtree==NULL) || (node==NULL) || (node==_NULL(rbtree))) 53 | { 54 | return; 55 | } 56 | /* the tree is empty */ 57 | if(rbtree->root == _NULL(rbtree)) 58 | { 59 | rbtree->root = node; 60 | node->parent = _NULL(rbtree); 61 | } 62 | else /* find the insert position */ 63 | { 64 | x = rbtree->root; 65 | while(x != _NULL(rbtree)) 66 | { 67 | y = x; 68 | if(node->key < x->key) x = x->left; 69 | else x = x->right; 70 | } 71 | /* now y is node's parent */ 72 | node->parent = y; 73 | if(node->key < y->key) y->left = node; 74 | else y->right = node; 75 | } 76 | 77 | /* initialize node's link & color */ 78 | node->left = _NULL(rbtree); 79 | node->right = _NULL(rbtree); 80 | util_rbt_red(node); 81 | /* fix up insert */ 82 | rbtree_insert_fixup(rbtree, node); 83 | rbtree->size++; 84 | } 85 | 86 | /* insert may violate the rbtree properties, fix up the tree */ 87 | void rbtree_insert_fixup(util_rbtree_t *rbtree, util_rbtree_node_t *node) 88 | { 89 | util_rbtree_node_t *p, *u; /* u is the uncle node of node */ 90 | while(util_rbt_isred(node->parent)) 91 | { 92 | p = node->parent; 93 | if(p == p->parent->left) /* parent is the left child */ 94 | { 95 | u = p->parent->right; 96 | if(util_rbt_isred(u)) /* case 1: p & u are red */ 97 | { 98 | util_rbt_black(u); 99 | util_rbt_black(p); 100 | util_rbt_red(p->parent); 101 | node = p->parent; 102 | } 103 | else 104 | { 105 | if(node == p->right) /* case 2: p:read, u:black, node is right child */ 106 | { 107 | node = p; 108 | rbtree_left_rotate(rbtree, node); 109 | p = node->parent; 110 | } 111 | /* case 3: p:read, u:black, node is left child */ 112 | util_rbt_black(p); 113 | util_rbt_red(p->parent); 114 | rbtree_right_rotate(rbtree, p->parent); 115 | } 116 | } 117 | else /* parent is the right child */ 118 | { 119 | u = p->parent->left; 120 | if(util_rbt_isred(u)) 121 | { 122 | util_rbt_black(u); 123 | util_rbt_black(p); 124 | util_rbt_red(p->parent); 125 | node = p->parent; 126 | } 127 | else 128 | { 129 | if(p->left == node) 130 | { 131 | node = p; 132 | rbtree_right_rotate(rbtree, node); 133 | p = node->parent; 134 | } 135 | util_rbt_black(p); 136 | util_rbt_red(p->parent); 137 | rbtree_left_rotate(rbtree, p->parent); 138 | } 139 | } 140 | } 141 | /* mark root to black */ 142 | util_rbt_black(rbtree->root); 143 | } 144 | 145 | 146 | void util_rbtree_delete(util_rbtree_t *rbtree, util_rbtree_node_t *node) 147 | { 148 | int isblack; 149 | util_rbtree_node_t *temp, *subst; 150 | if((rbtree==NULL) || (node==NULL) || (node==_NULL(rbtree))) 151 | { 152 | return; 153 | } 154 | rbtree->size--; 155 | /* find deleted position, indicated by temp */ 156 | if(node->left == _NULL(rbtree)) 157 | { 158 | temp = node; 159 | subst = node->right; 160 | } 161 | else if(node->right == _NULL(rbtree)) 162 | { 163 | temp = node; 164 | subst = node->left; 165 | } 166 | else /* right & left aren't null */ 167 | { 168 | temp = util_rbsubtree_min(node->right, _NULL(rbtree)); 169 | if(temp->left != _NULL(rbtree)) 170 | { 171 | subst = temp->left; 172 | } 173 | else 174 | { 175 | subst = temp->right; 176 | } 177 | } 178 | if(temp == rbtree->root) /* temp is root */ 179 | { 180 | rbtree->root = subst; 181 | util_rbt_black(subst); 182 | rbt_clear_node(temp); 183 | return; 184 | } 185 | isblack = util_rbt_isblack(temp); 186 | /* temp will be removed from it's position, rebuild links 187 | * NOTE: if temp->parent = node, then subst->parent is node 188 | * while node is the one to be delete, so relink subst's parent to temp 189 | * because temp will replace node's in the tree 190 | */ 191 | if(temp->parent == node) 192 | { 193 | subst->parent = temp; 194 | } 195 | else 196 | { 197 | subst->parent = temp->parent; 198 | } 199 | 200 | if(temp == temp->parent->left) 201 | { 202 | temp->parent->left = subst; 203 | } 204 | else 205 | { 206 | temp->parent->right = subst; 207 | } 208 | /* 209 | * now temp is removed from the tree. 210 | * so we will make temp to replace node in the tree. 211 | */ 212 | if(temp != node) 213 | { 214 | temp->parent = node->parent; 215 | if(node == rbtree->root) /* node maybe root */ 216 | { 217 | rbtree->root = temp; 218 | } 219 | else 220 | { 221 | if(node->parent->left == node) 222 | { 223 | node->parent->left = temp; 224 | } 225 | else 226 | { 227 | node->parent->right = temp; 228 | } 229 | } 230 | temp->right = node->right; 231 | temp->left = node->left; 232 | if(temp->left != _NULL(rbtree)) 233 | { 234 | temp->left->parent = temp; 235 | } 236 | if(temp->right != _NULL(rbtree)) 237 | { 238 | temp->right->parent = temp; 239 | } 240 | temp->color = node->color; 241 | } 242 | rbt_clear_node(node); 243 | 244 | if(isblack) 245 | { 246 | /* temp is black, fix up delete */ 247 | rbtree_delete_fixup(rbtree, subst); 248 | } 249 | } 250 | 251 | /* delete may violate the rbtree properties, fix up the tree */ 252 | void rbtree_delete_fixup(util_rbtree_t *rbtree, util_rbtree_node_t *node) 253 | { 254 | int h = 0; 255 | util_rbtree_node_t *w; 256 | while((node != rbtree->root) && util_rbt_isblack(node)) 257 | { 258 | h++; 259 | if(node == node->parent->left) /* node is left child */ 260 | { 261 | w = node->parent->right; 262 | if(util_rbt_isred(w)) 263 | { 264 | util_rbt_black(w); 265 | util_rbt_red(node->parent); 266 | rbtree_left_rotate(rbtree, node->parent); 267 | w = node->parent->right; 268 | } 269 | if(util_rbt_isblack(w->left) && util_rbt_isblack(w->right)) 270 | { 271 | util_rbt_red(w); 272 | node = node->parent; 273 | } 274 | else 275 | { 276 | if(util_rbt_isblack(w->right)) 277 | { 278 | util_rbt_black(w->left); 279 | util_rbt_red(w); 280 | rbtree_right_rotate(rbtree, w); 281 | w = node->parent->right; 282 | } 283 | w->color = node->parent->color; 284 | util_rbt_black(node->parent); 285 | util_rbt_black(w->right); 286 | rbtree_left_rotate(rbtree, node->parent); 287 | node = rbtree->root; /* to break loop */ 288 | } 289 | } 290 | else /* node is right child */ 291 | { 292 | w = node->parent->left; 293 | if(w == 0) 294 | { 295 | int t = 4; 296 | } 297 | if(util_rbt_isred(w)) 298 | { 299 | util_rbt_black(w); 300 | util_rbt_red(node->parent); 301 | rbtree_right_rotate(rbtree, node->parent); 302 | w = node->parent->left; 303 | } 304 | if(util_rbt_isblack(w->left) && util_rbt_isblack(w->right)) 305 | { 306 | util_rbt_red(w); 307 | node = node->parent; 308 | } 309 | else 310 | { 311 | if(util_rbt_isblack(w->left)) 312 | { 313 | util_rbt_black(w->right); 314 | util_rbt_red(w); 315 | rbtree_left_rotate(rbtree, w); 316 | w = node->parent->left; 317 | } 318 | w->color = node->parent->color; 319 | util_rbt_black(node->parent); 320 | util_rbt_black(w->left); 321 | rbtree_right_rotate(rbtree, node->parent); 322 | node = rbtree->root; /* to break loop */ 323 | } 324 | } 325 | } 326 | util_rbt_black(node); 327 | } 328 | 329 | void rbtree_left_rotate(util_rbtree_t *rbtree, util_rbtree_node_t *node) 330 | { 331 | util_rbtree_node_t *rc = node->right; 332 | util_rbtree_node_t *rclc = rc->left; 333 | /* make rc to replace node's position */ 334 | rc->parent = node->parent; 335 | if(node == rbtree->root) 336 | { 337 | rbtree->root = rc; 338 | } 339 | else 340 | { 341 | if(node->parent->left == node) /* node is left child */ 342 | { 343 | node->parent->left = rc; 344 | } 345 | else 346 | { 347 | node->parent->right = rc; 348 | } 349 | } 350 | /* make node to be rc's left child */ 351 | node->parent = rc; 352 | rc->left = node; 353 | /* rc's left child to be node's right child */ 354 | node->right = rclc; 355 | if(rclc != _NULL(rbtree)) 356 | { 357 | rclc->parent = node; 358 | } 359 | } 360 | 361 | void rbtree_right_rotate(util_rbtree_t *rbtree, util_rbtree_node_t *node) 362 | { 363 | util_rbtree_node_t *lc = node->left; 364 | util_rbtree_node_t *lcrc = lc->right; 365 | /* make lc to replace node's position */ 366 | lc->parent = node->parent; 367 | if(node == rbtree->root) 368 | { 369 | rbtree->root = lc; 370 | } 371 | else 372 | { 373 | if(node->parent->left == node) /* node is left child */ 374 | { 375 | node->parent->left = lc; 376 | } 377 | else 378 | { 379 | node->parent->right = lc; 380 | } 381 | } 382 | /* make node to be lc's right child */ 383 | lc->right = node; 384 | node->parent = lc; 385 | /* lc's right child to be node's left child */ 386 | node->left = lcrc; 387 | if(lcrc != _NULL(rbtree)) 388 | { 389 | lcrc->parent = node; 390 | } 391 | } 392 | 393 | util_rbtree_node_t* util_rbtree_search(util_rbtree_t *rbtree, long key) 394 | { 395 | if(rbtree != NULL) 396 | { 397 | util_rbtree_node_t *node = rbtree->root; 398 | util_rbtree_node_t *null = _NULL(rbtree); 399 | while(node != null) 400 | { 401 | if(key < node->key) node = node->left; 402 | else if(key > node->key) node = node->right; 403 | else if(node->key == key) return node; 404 | } 405 | } 406 | return NULL; 407 | } 408 | 409 | util_rbtree_node_t* util_rbtree_lookup(util_rbtree_t *rbtree, long key) 410 | { 411 | if((rbtree != NULL) && !util_rbtree_isempty(rbtree)) 412 | { 413 | util_rbtree_node_t *node = NULL; 414 | util_rbtree_node_t *temp = rbtree->root; 415 | util_rbtree_node_t *null = _NULL(rbtree); 416 | while(temp != null) 417 | { 418 | if(key <= temp->key) 419 | { 420 | node = temp; /* update node */ 421 | temp = temp->left; 422 | } 423 | else if(key > temp->key) 424 | { 425 | temp = temp->right; 426 | } 427 | } 428 | /* if node==NULL return the minimum node */ 429 | return ((node != NULL) ? node : util_rbtree_min(rbtree)); 430 | } 431 | return NULL; 432 | } 433 | 434 | static void rbtree_check_subtree(const util_rbtree_node_t *node, rbtree_check_t *check, 435 | int level, int curheight) 436 | { 437 | if(check->fini) /* already failed */ 438 | { 439 | return; 440 | } 441 | /* check node color */ 442 | if(util_rbt_isblack(node)) 443 | { 444 | curheight++; 445 | } 446 | else if(!util_rbt_isred(node)) 447 | { 448 | check->fini = 2; 449 | return; 450 | } 451 | /* check left */ 452 | if(node->left != check->null) 453 | { 454 | if(util_rbt_isred(node) && util_rbt_isred(node->left)) 455 | { 456 | check->fini = 4; 457 | return; 458 | } 459 | if(node->key < node->left->key) 460 | { 461 | check->fini = 5; 462 | return; 463 | } 464 | rbtree_check_subtree(node->left, check, level+1, curheight); 465 | } 466 | else 467 | { 468 | goto __check_rb_height; 469 | } 470 | /* check right */ 471 | if(node->right != check->null) 472 | { 473 | if(util_rbt_isred(node) && util_rbt_isred(node->right)) 474 | { 475 | check->fini = 4; 476 | return; 477 | } 478 | if(node->key > node->right->key) 479 | { 480 | check->fini = 5; 481 | return; 482 | } 483 | rbtree_check_subtree(node->right, check, level+1, curheight); 484 | } 485 | else 486 | { 487 | goto __check_rb_height; 488 | } 489 | return; 490 | __check_rb_height: 491 | if(check->rbh == 0) 492 | { 493 | check->rbh = curheight; 494 | } 495 | if(check->maxd < level) 496 | { 497 | check->maxd = level; 498 | } 499 | if(check->rbh != curheight) 500 | { 501 | check->fini = 3; 502 | } 503 | } 504 | 505 | int util_rbtree_check(const util_rbtree_t *rbtree, int *blackheight, int *maxdepth) 506 | { 507 | rbtree_check_t check; 508 | if(rbtree->root == _NULL(rbtree)) 509 | { 510 | return 0; 511 | } 512 | if(!util_rbt_isblack(rbtree->root)) 513 | { 514 | return 1; 515 | } 516 | check.fini = check.maxd = check.rbh = 0; 517 | check.null = _NULL(rbtree); 518 | rbtree_check_subtree(rbtree->root, &check, 1, 0); 519 | if(blackheight) 520 | { 521 | *blackheight = check.rbh; 522 | } 523 | if(maxdepth) 524 | { 525 | *maxdepth = check.maxd; 526 | } 527 | return check.fini; 528 | } 529 | 530 | static void rbtree_mid_travel(util_rbtree_node_t *node, util_rbtree_node_t *sentinel, 531 | void(*opera)(util_rbtree_node_t *, void *), void *data) 532 | { 533 | if(node->left != sentinel) 534 | { 535 | rbtree_mid_travel(node->left, sentinel, opera, data); 536 | } 537 | opera(node, data); 538 | if(node->right != sentinel) 539 | { 540 | rbtree_mid_travel(node->right, sentinel, opera, data); 541 | } 542 | } 543 | 544 | void util_rbtree_mid_travel(util_rbtree_t *rbtree, 545 | void(*opera)(util_rbtree_node_t *, void *), void *data) 546 | { 547 | if((rbtree!=NULL) && !util_rbtree_isempty(rbtree)) 548 | { 549 | rbtree_mid_travel(rbtree->root, _NULL(rbtree), opera, data); 550 | } 551 | } 552 | -------------------------------------------------------------------------------- /src/util_rbtree.h: -------------------------------------------------------------------------------- 1 | 2 | /* Copyright (C) 2010. sparkling.liang@hotmail.com. All rights reserved. */ 3 | 4 | #ifndef __UTIL_RLTREE_H_ 5 | #define __UTIL_RLTREE_H_ 6 | 7 | #include "configure.h" 8 | #include 9 | 10 | typedef struct util_rbtree_s util_rbtree_t; 11 | typedef struct util_rbtree_node_s util_rbtree_node_t; 12 | 13 | struct util_rbtree_node_s 14 | { 15 | long key; 16 | util_rbtree_node_t *parent; 17 | util_rbtree_node_t *right; 18 | util_rbtree_node_t *left; 19 | int color; 20 | void *data; 21 | }; 22 | 23 | struct util_rbtree_s 24 | { 25 | util_rbtree_node_t *root; 26 | util_rbtree_node_t null; 27 | u_int size; 28 | }; 29 | 30 | 31 | #define util_rbt_black(rbnode) ((rbnode)->color = 1) 32 | #define util_rbt_red(rbnode) ((rbnode)->color = 0) 33 | #define util_rbt_isblack(rbnode) ((rbnode)->color == 1) 34 | #define util_rbt_isred(rbnode) ((rbnode)->color == 0) 35 | 36 | /* clear a node's link */ 37 | #define rbt_clear_node(node) do{ \ 38 | node->left = NULL; \ 39 | node->right = NULL; \ 40 | node->parent = NULL; \ 41 | }while(0) 42 | 43 | /* is the tree empty */ 44 | #define util_rbtree_isempty(rbtree) ((rbtree)->root == &(rbtree)->null) 45 | 46 | /* 47 | * find the min node of tree 48 | * return NULL is tree is empty 49 | */ 50 | #define util_rbtree_min(rbtree) util_rbsubtree_min((rbtree)->root, &(rbtree)->null) 51 | 52 | /* 53 | * find the max node of tree 54 | * return NULL is tree is empty 55 | */ 56 | #define util_rbtree_max(rbtree) util_rbsubtree_max((rbtree)->root, &(rbtree)->null) 57 | 58 | void util_rbtree_init(util_rbtree_t *rbtree); 59 | void util_rbtree_insert(util_rbtree_t *rbtree, util_rbtree_node_t *node); 60 | void util_rbtree_delete(util_rbtree_t *rbtree, util_rbtree_node_t *node); 61 | 62 | /* 63 | * search node with key = @key in the tree 64 | * if no such node exist, return NULL 65 | */ 66 | util_rbtree_node_t* util_rbtree_search(util_rbtree_t *rbtree, long key); 67 | 68 | /* 69 | * look node in the tree 70 | * return the first node with key >= @key; 71 | * if @key > all the key values in the tree, return the node with minimum key 72 | * return NULL if tree is empty 73 | */ 74 | util_rbtree_node_t* util_rbtree_lookup(util_rbtree_t *rbtree, long key); 75 | 76 | /* 77 | * find the min node of subtree 78 | * @rbnode: root of the subtree 79 | * @sentinel : the sentinel node 80 | * return NULL if subtree is empty 81 | */ 82 | util_rbtree_node_t* util_rbsubtree_min(util_rbtree_node_t *node, util_rbtree_node_t *sentinel); 83 | 84 | /* 85 | * find the max node of subtree 86 | * @rbnode: root of the subtree 87 | * @sentinel : the sentinel node 88 | * return NULL if subtree is empty 89 | */ 90 | util_rbtree_node_t* util_rbsubtree_max(util_rbtree_node_t *node, util_rbtree_node_t *sentinel); 91 | 92 | /* 93 | * check whether a tree is a rb tree, the null node is n't checked 94 | * return 0: yes 95 | * return 1: root isn't black 96 | * return 2: node is in other color than black and red 97 | * return 3: tree's black height isn't unique 98 | * return 4: a red node with parent in red exists 99 | * return 5: volatile binary search properties 100 | * 101 | * when return !0, @blackheight & @maxdepth is uselsess 102 | * when return 0, @blackheight contains the tree's black height 103 | * 104 | * @maxdepth contains the max length of all simple roads from root to it's leaf nodes 105 | */ 106 | int util_rbtree_check(const util_rbtree_t *rbtree, int *blackheight, int *maxdepth); 107 | 108 | /* 109 | * travel through a rb tree in sequence: left-root-right 110 | * you CAN NOT do any operations that will break the RB properties 111 | */ 112 | void util_rbtree_mid_travel(util_rbtree_t *rbtree, void(*opera)(util_rbtree_node_t *, void *), void *data); 113 | 114 | #endif /* end __UTIL_RLTREE_H_ */ 115 | --------------------------------------------------------------------------------